235 lines
4.7 KiB
C
235 lines
4.7 KiB
C
#undef DEBUG
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <dm/device.h>
|
|
#include <dm/ofnode.h>
|
|
#include <asm/gpio.h>
|
|
#include <asm/io.h>
|
|
#include <errno.h>
|
|
#include "../common/nbhw_bd.h"
|
|
#include "../common/nbhw_sim.h"
|
|
#include "nbhw_gpio.h"
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
struct gpio_desc leds[16];
|
|
struct udevice *driver_dev;
|
|
|
|
struct config_priv {
|
|
u32 led_count;
|
|
} priv;
|
|
|
|
typedef enum {
|
|
TYPE_USB,
|
|
TYPE_USB3,
|
|
TYPE_PCIE,
|
|
} slot_type_t;
|
|
|
|
struct pcie_slot_gpios {
|
|
struct gpio_desc reset;
|
|
struct gpio_desc power;
|
|
struct gpio_desc wdis_out;
|
|
struct gpio_desc wdis;
|
|
};
|
|
|
|
#define PCIE_SLOT_COUNT 8
|
|
static struct pcie_slot_gpios pcie_slots[PCIE_SLOT_COUNT];
|
|
|
|
static int pcie_slot_count = 0;
|
|
|
|
int pcie_lane_by_slot(int slot);
|
|
|
|
static int request_and_set_gpio_by_name(ofnode fdt,
|
|
const char *name, struct gpio_desc *desc)
|
|
{
|
|
int default_value = 0;
|
|
u32 gpio_array[4];
|
|
debug("%s\n", __func__);
|
|
|
|
/* Request the gpio described by the property */
|
|
if (gpio_request_by_name_nodev(fdt, name, 0, desc,
|
|
GPIOD_IS_OUT))
|
|
{
|
|
debug("Could not request gpio %s\n", name);
|
|
return -1;
|
|
}
|
|
|
|
/* Get the gpio array, to find out its default value (4 index) */
|
|
if (ofnode_read_u32_array(fdt, name, gpio_array, 4)) {
|
|
printf("Could not request gpio array %s\n", name);
|
|
return -1;
|
|
|
|
}
|
|
|
|
default_value = gpio_array[3];
|
|
debug("Set GPIO %s to %d\n", name, default_value);
|
|
dm_gpio_set_value(desc, default_value);
|
|
return 0;
|
|
}
|
|
|
|
static int add_pcie_slot(ofnode fdt)
|
|
{
|
|
debug("%s\n", __func__);
|
|
|
|
request_and_set_gpio_by_name(fdt, "power",
|
|
&pcie_slots[pcie_slot_count].power);
|
|
|
|
request_and_set_gpio_by_name(fdt, "reset",
|
|
&pcie_slots[pcie_slot_count].reset);
|
|
|
|
request_and_set_gpio_by_name(fdt, "wdis-out",
|
|
&pcie_slots[pcie_slot_count].wdis_out);
|
|
|
|
request_and_set_gpio_by_name(fdt, "wdis",
|
|
&pcie_slots[pcie_slot_count].wdis);
|
|
|
|
pcie_slot_count++;
|
|
return 0;
|
|
}
|
|
|
|
static void configure_pcie_muxes(void)
|
|
{
|
|
/* Disable PCI clock and serdes4 routing unless
|
|
explicitly requested later. */
|
|
set_gpio(GPIO_SERDES4_MUX_EN, 0);
|
|
set_gpio(GPIO_PEX2_CLK_1_4_MUX_EN, 0);
|
|
|
|
/* Check for PCIe on slot 1 */
|
|
if (pcie_lane_by_slot(1) >= 0) {
|
|
// PEX2 is on slot 1
|
|
|
|
// mux serdes4 to slot 1 pci pins
|
|
set_gpio(GPIO_SERDES4_MUX_SEL, 1);
|
|
set_gpio(GPIO_SERDES4_MUX_EN, 1);
|
|
// route PEX2 clock to slot 1
|
|
set_gpio(GPIO_PEX2_CLK_1_4_MUX_SEL, 1);
|
|
set_gpio(GPIO_PEX2_CLK_1_4_MUX_EN, 1);
|
|
} else {
|
|
// mux serdes4 to slot 1 usb 3.0 pins
|
|
set_gpio(GPIO_SERDES4_MUX_SEL, 0);
|
|
set_gpio(GPIO_SERDES4_MUX_EN, 1);
|
|
}
|
|
|
|
/* Check for PCIe on slot 4 */
|
|
if (pcie_lane_by_slot(4) >= 0) {
|
|
// PEX2 is on slot 4
|
|
|
|
// route PEX2 clock to slot 4
|
|
set_gpio(GPIO_PEX2_CLK_1_4_MUX_SEL, 0);
|
|
set_gpio(GPIO_PEX2_CLK_1_4_MUX_EN, 1);
|
|
}
|
|
}
|
|
|
|
static int configure_pcie_slots(void)
|
|
{
|
|
int i;
|
|
|
|
configure_pcie_muxes();
|
|
configure_sim_slots(6);
|
|
|
|
udelay(1200000); /* 1.2 s */
|
|
|
|
/* Apply power to all PCIe slots */
|
|
for (i = 0; i < pcie_slot_count; i++) {
|
|
dm_gpio_set_value(&pcie_slots[i].power, 1);
|
|
udelay(200000); /* 200 ms */
|
|
}
|
|
|
|
/* Assert reset after power is enabled */
|
|
for (i = 0; i < pcie_slot_count; i++) {
|
|
dm_gpio_set_value(&pcie_slots[i].reset, 1);
|
|
}
|
|
|
|
/* Deactivate WDIS */
|
|
for (i = 0; i < pcie_slot_count; i++) {
|
|
dm_gpio_set_value(&pcie_slots[i].wdis_out, 1);
|
|
dm_gpio_set_value(&pcie_slots[i].wdis, 0);
|
|
udelay(2000); /* 2 ms needed by Reyax module as regulator is enabled by WDIS~*/
|
|
}
|
|
|
|
udelay(12000); /* 12 ms */
|
|
|
|
/* Deassert reset */
|
|
for (i = 0; i < pcie_slot_count; i++) {
|
|
dm_gpio_set_value(&pcie_slots[i].reset, 0);
|
|
}
|
|
|
|
pci_init_board();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int configure_leds(void)
|
|
{
|
|
int i;
|
|
int led_count;
|
|
|
|
led_count = gpio_request_list_by_name(driver_dev, "leds", leds,
|
|
ARRAY_SIZE(leds), GPIOD_IS_OUT);
|
|
|
|
dm_gpio_set_value(&leds[0], 1);
|
|
for (i = 1; i < ARRAY_SIZE(leds); i++) {
|
|
dm_gpio_set_value(&leds[i], 0);
|
|
}
|
|
|
|
priv.led_count = led_count;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void set_led(int index, int value)
|
|
{
|
|
if ((index<0) || (index>=priv.led_count)) return;
|
|
|
|
dm_gpio_set_value(&leds[index], value);
|
|
}
|
|
|
|
int nbhw_fpga_configure(void)
|
|
{
|
|
ofnode subnode;
|
|
ofnode node = driver_dev->node;
|
|
debug("%s\n", __func__);
|
|
|
|
ofnode_for_each_subnode(subnode, node) {
|
|
const char *name;
|
|
|
|
name = ofnode_get_name(subnode);
|
|
|
|
debug("Try to configure %s\n", name);
|
|
|
|
if (!strncmp("pcieslot", name, 8)) {
|
|
add_pcie_slot(subnode);
|
|
}
|
|
}
|
|
|
|
if (configure_leds())
|
|
return -1;
|
|
|
|
if (configure_pcie_slots()) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nbhw_fpga_config_bind(struct udevice *dev)
|
|
{
|
|
debug("%s\n", __func__);
|
|
|
|
driver_dev = dev;
|
|
return 0;
|
|
}
|
|
|
|
static const struct udevice_id nbhw_fpga_config_ids[] = {
|
|
{ .compatible = "nm,hw14-fpga-config" },
|
|
{ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(gpio_nbhw_fpga_config) = {
|
|
.name = "hw14_fpga_config",
|
|
.id = UCLASS_ROOT,
|
|
.of_match = nbhw_fpga_config_ids,
|
|
.bind = nbhw_fpga_config_bind,
|
|
};
|
|
|