u-boot/board/nm/hw29/nbhw_fpga_config.c

394 lines
8.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"
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;
struct gpio_desc clk;
struct gpio_desc power_3v8;
struct gpio_desc reset_1v8;
struct gpio_desc reset_3v3;
struct gpio_desc wdis_1v8;
struct gpio_desc wdis_3v3;
};
struct sfp_gpios {
struct gpio_desc reset;
struct gpio_desc power;
};
#define PCIE_SLOT_COUNT 8
static struct pcie_slot_gpios pcie_slots[PCIE_SLOT_COUNT];
static struct sfp_gpios sfps;
static int pcie_slot_count = 0;
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_sfp(ofnode fdt)
{
debug("%s\n", __func__);
request_and_set_gpio_by_name(fdt, "power",
&sfps.power);
request_and_set_gpio_by_name(fdt, "reset",
&sfps.reset);
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);
request_and_set_gpio_by_name(fdt, "clk",
&pcie_slots[pcie_slot_count].clk);
request_and_set_gpio_by_name(fdt, "power-3v8",
&pcie_slots[pcie_slot_count].power_3v8);
request_and_set_gpio_by_name(fdt, "reset-1v8",
&pcie_slots[pcie_slot_count].reset_1v8);
request_and_set_gpio_by_name(fdt, "reset-3v3",
&pcie_slots[pcie_slot_count].reset_3v3);
request_and_set_gpio_by_name(fdt, "wdis-1v8",
&pcie_slots[pcie_slot_count].wdis_1v8);
request_and_set_gpio_by_name(fdt, "wdis-3v3",
&pcie_slots[pcie_slot_count].wdis_3v3);
pcie_slot_count++;
return 0;
}
static int has_slot_wlan(int slot)
{
int module;
char slotDescr[20];
char pdValue[200];
sprintf(slotDescr, "slot=%d", slot);
for (module=0; module<4; module++) {
strcpy(pdValue, "" ); /*init with an empty string*/
if (bd_get_pd_module(module, pdValue, sizeof(pdValue))==0) {
/* Wifi module needs PCIe */
if ((strstr(pdValue, slotDescr)) && (strstr(pdValue, "wlan-")))
return 1;
}
}
return 0;
}
static int configure_pcie_slots(void)
{
int i, res;
char volt[10];
configure_sim_slots(4);
udelay(1200000); /* 1.2 s */
for (i = 0; i < 5; i++) {
/* Set supply voltage of PCIe slots */
if ((bd_get_slot_supply_volt(i, volt, sizeof(volt)) == 0) &&
(strncmp(volt, "3v8", 3)==0)) {
dm_gpio_set_value(&pcie_slots[i].power_3v8, 1);
} else {
/* Default is 3v3 */
dm_gpio_set_value(&pcie_slots[i].power_3v8, 0);
}
/* Set reset signal voltage of PCIe slots */
res = bd_get_slot_perst_volt(i, volt, sizeof(volt));
if ((res == 0) && (strncmp(volt, "off", 3)==0)) {
/* No pull up */
dm_gpio_set_value(&pcie_slots[i].reset_1v8, 0);
dm_gpio_set_value(&pcie_slots[i].reset_3v3, 0);
} else if ((res == 0) && (strncmp(volt, "1v8", 3)==0)) {
dm_gpio_set_value(&pcie_slots[i].reset_1v8, 1);
dm_gpio_set_value(&pcie_slots[i].reset_3v3, 0);
} else {
/* Default is 3v3 */
dm_gpio_set_value(&pcie_slots[i].reset_1v8, 0);
dm_gpio_set_value(&pcie_slots[i].reset_3v3, 1);
}
/* Set wdis signal voltage of PCIe slots */
res = bd_get_slot_wdis_volt(i, volt, sizeof(volt));
if ((res == 0) && (strncmp(volt, "off", 3)==0)) {
/* No pull up */
dm_gpio_set_value(&pcie_slots[i].wdis_1v8, 0);
dm_gpio_set_value(&pcie_slots[i].wdis_3v3, 0);
} else if ((res == 0) && (strncmp(volt, "1v8", 3)==0)) {
dm_gpio_set_value(&pcie_slots[i].wdis_1v8, 1);
dm_gpio_set_value(&pcie_slots[i].wdis_3v3, 0);
} else {
/* Default is 3v3 */
dm_gpio_set_value(&pcie_slots[i].wdis_1v8, 0);
dm_gpio_set_value(&pcie_slots[i].wdis_3v3, 1);
}
}
/* 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);
}
/* Enable PCIe clock Note: Slot 1 has always clock. Slot 0 & extension
slot cannot have clock at same time. */
for (i = 0; i < 2; i ++) {
if (has_slot_wlan(i)) {
/* Only enable PCIe clock on WiFi modules as it confuses some LTE modems */
dm_gpio_set_value(&pcie_slots[i].clk, 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);
}
static int request_and_set_gpios(ofnode fdt,
struct gpio_desc *gpios, u32 max_gpios)
{
int i = 0;
int default_value = 0;
int offset = 0;
for (offset = fdt_first_property_offset(gd->fdt_blob, ofnode_to_offset(fdt));
offset >= 0;
offset = fdt_next_property_offset(gd->fdt_blob, offset)) {
u32 gpio_array[4];
const char *name;
const struct fdt_property *prop;
if (i >= max_gpios) {
printf("Too many gpio entries (max %d)\n", max_gpios);
break;
}
prop = fdt_get_property_by_offset(gd->fdt_blob, offset, NULL);
name = fdt_string(gd->fdt_blob, fdt32_to_cpu(prop->nameoff));
debug("Name: %s\n", name);
if (name[0] == '#') {
continue;
}
/* Request the gpio descriped by the property */
if (gpio_request_by_name_nodev(fdt, name, 0, &gpios[i],
GPIOD_IS_OUT))
{
printf("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(&gpios[i], default_value);
i++;
}
debug("leave %s with %d gpios\n", __func__, i);
return i;
}
static int configure_misc(ofnode fdt)
{
struct gpio_desc misc_gpios[16];
int gpio_count;
debug("%s\n", __func__);
gpio_count = request_and_set_gpios(fdt,
misc_gpios, ARRAY_SIZE(misc_gpios));
if (gpio_count < 1) {
return -1;
}
debug("Free gpios\n");
/* Free gpios so that we could use them via gpio subsystem */
gpio_free_list_nodev(misc_gpios, gpio_count);
debug("return %s\n", __func__);
return 0;
}
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("misc", name, 4)) {
configure_misc(subnode);
}
if (!strncmp("pcieslot", name, 8)) {
add_pcie_slot(subnode);
}
if (!strncmp("sfp", name, 3)) {
add_sfp(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,nbhw29-fpga-config" },
{ }
};
U_BOOT_DRIVER(gpio_nbhw_fpga_config) = {
.name = "nbhw29_fpga_config",
.id = UCLASS_ROOT,
.of_match = nbhw_fpga_config_ids,
.bind = nbhw_fpga_config_bind,
};