X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fraw%2Fifpga%2Fbase%2Fopae_intel_max10.c;h=8e23ca18a76107931547504bcbac87b3d6fb8780;hb=05b6eee7bdabf7c17ed69c44515e0cd7d6e1da23;hp=305baba8d4c97dfb9d0f63ecf30edbadbc301199;hpb=e1defba4cf6689eadc78693a8253d0c8a8d56c00;p=dpdk.git diff --git a/drivers/raw/ifpga/base/opae_intel_max10.c b/drivers/raw/ifpga/base/opae_intel_max10.c index 305baba8d4..8e23ca18a7 100644 --- a/drivers/raw/ifpga/base/opae_intel_max10.c +++ b/drivers/raw/ifpga/base/opae_intel_max10.c @@ -5,28 +5,52 @@ #include "opae_intel_max10.h" #include -static struct intel_max10_device *g_max10; - -int max10_reg_read(unsigned int reg, unsigned int *val) +int max10_reg_read(struct intel_max10_device *dev, + unsigned int reg, unsigned int *val) { - if (!g_max10) + if (!dev) return -ENODEV; - return spi_transaction_read(g_max10->spi_tran_dev, + dev_debug(dev, "%s: bus:0x%x, reg:0x%x\n", __func__, dev->bus, reg); + + return spi_transaction_read(dev->spi_tran_dev, reg, 4, (unsigned char *)val); } -int max10_reg_write(unsigned int reg, unsigned int val) +int max10_reg_write(struct intel_max10_device *dev, + unsigned int reg, unsigned int val) { unsigned int tmp = val; - if (!g_max10) + if (!dev) return -ENODEV; - return spi_transaction_write(g_max10->spi_tran_dev, + dev_debug(dev, "%s: bus:0x%x, reg:0x%x, val:0x%x\n", __func__, + dev->bus, reg, val); + + return spi_transaction_write(dev->spi_tran_dev, reg, 4, (unsigned char *)&tmp); } +int max10_sys_read(struct intel_max10_device *dev, + unsigned int offset, unsigned int *val) +{ + if (!dev) + return -ENODEV; + + + return max10_reg_read(dev, dev->base + offset, val); +} + +int max10_sys_write(struct intel_max10_device *dev, + unsigned int offset, unsigned int val) +{ + if (!dev) + return -ENODEV; + + return max10_reg_write(dev, dev->base + offset, val); +} + static struct max10_compatible_id max10_id_table[] = { {.compatible = MAX10_PAC,}, {.compatible = MAX10_PAC_N3000,}, @@ -63,11 +87,12 @@ static void max10_check_capability(struct intel_max10_device *max10) max10->flags |= MAX10_FLAGS_NO_I2C2 | MAX10_FLAGS_NO_BMCIMG_FLASH; dev_info(max10, "found %s card\n", max10->id->compatible); - } + } else + max10->flags |= MAX10_FLAGS_MAC_CACHE; } -static int altera_nor_flash_read(u32 offset, - void *buffer, u32 len) +static int altera_nor_flash_read(struct intel_max10_device *dev, + u32 offset, void *buffer, u32 len) { int word_len; int i; @@ -75,13 +100,13 @@ static int altera_nor_flash_read(u32 offset, unsigned int value; int ret; - if (!buffer || len <= 0) + if (!dev || !buffer || len <= 0) return -ENODEV; word_len = len/4; for (i = 0; i < word_len; i++) { - ret = max10_reg_read(offset + i*4, + ret = max10_reg_read(dev, offset + i*4, &value); if (ret) return -EBUSY; @@ -92,12 +117,12 @@ static int altera_nor_flash_read(u32 offset, return 0; } -static int enable_nor_flash(bool on) +static int enable_nor_flash(struct intel_max10_device *dev, bool on) { unsigned int val = 0; int ret; - ret = max10_reg_read(RSU_REG_OFF, &val); + ret = max10_sys_read(dev, RSU_REG, &val); if (ret) { dev_err(NULL "enabling flash error\n"); return ret; @@ -108,7 +133,7 @@ static int enable_nor_flash(bool on) else val &= ~RSU_ENABLE; - return max10_reg_write(RSU_REG_OFF, val); + return max10_sys_write(dev, RSU_REG, val); } static int init_max10_device_table(struct intel_max10_device *max10) @@ -120,7 +145,7 @@ static int init_max10_device_table(struct intel_max10_device *max10) u32 dt_size, dt_addr, val; int ret; - ret = max10_reg_read(DT_AVAIL_REG_OFF, &val); + ret = max10_sys_read(max10, DT_AVAIL_REG, &val); if (ret) { dev_err(max10 "cannot read DT_AVAIL_REG\n"); return ret; @@ -131,19 +156,19 @@ static int init_max10_device_table(struct intel_max10_device *max10) return -EINVAL; } - ret = max10_reg_read(DT_BASE_ADDR_REG_OFF, &dt_addr); + ret = max10_sys_read(max10, DT_BASE_ADDR_REG, &dt_addr); if (ret) { dev_info(max10 "cannot get base addr of device table\n"); return ret; } - ret = enable_nor_flash(true); + ret = enable_nor_flash(max10, true); if (ret) { dev_err(max10 "fail to enable flash\n"); return ret; } - ret = altera_nor_flash_read(dt_addr, &hdr, sizeof(hdr)); + ret = altera_nor_flash_read(max10, dt_addr, &hdr, sizeof(hdr)); if (ret) { dev_err(max10 "read fdt header fail\n"); goto done; @@ -168,7 +193,7 @@ static int init_max10_device_table(struct intel_max10_device *max10) goto done; } - ret = altera_nor_flash_read(dt_addr, fdt_root, dt_size); + ret = altera_nor_flash_read(max10, dt_addr, fdt_root, dt_size); if (ret) { dev_err(max10 "cannot read device table\n"); goto done; @@ -187,7 +212,7 @@ static int init_max10_device_table(struct intel_max10_device *max10) max10->fdt_root = fdt_root; done: - ret = enable_nor_flash(false); + ret = enable_nor_flash(max10, false); if (ret && fdt_root) opae_free(fdt_root); @@ -195,6 +220,348 @@ done: return ret; } +static u64 fdt_get_number(const fdt32_t *cell, int size) +{ + u64 r = 0; + + while (size--) + r = (r << 32) | fdt32_to_cpu(*cell++); + + return r; +} + +static int fdt_get_reg(const void *fdt, int node, unsigned int idx, + u64 *start, u64 *size) +{ + const fdt32_t *prop, *end; + int na = 0, ns = 0, len = 0, parent; + + parent = fdt_parent_offset(fdt, node); + if (parent < 0) + return parent; + + prop = fdt_getprop(fdt, parent, "#address-cells", NULL); + na = prop ? fdt32_to_cpu(*prop) : 2; + + prop = fdt_getprop(fdt, parent, "#size-cells", NULL); + ns = prop ? fdt32_to_cpu(*prop) : 2; + + prop = fdt_getprop(fdt, node, "reg", &len); + if (!prop) + return -FDT_ERR_NOTFOUND; + + end = prop + len/sizeof(*prop); + prop = prop + (na + ns) * idx; + + if (prop + na + ns > end) + return -FDT_ERR_NOTFOUND; + + *start = fdt_get_number(prop, na); + *size = fdt_get_number(prop + na, ns); + + return 0; +} + +static int __fdt_stringlist_search(const void *fdt, int offset, + const char *prop, const char *string) +{ + int length, len, index = 0; + const char *list, *end; + + list = fdt_getprop(fdt, offset, prop, &length); + if (!list) + return length; + + len = strlen(string) + 1; + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + if (list + length > end) + return -FDT_ERR_BADVALUE; + + if (length == len && memcmp(list, string, length) == 0) + return index; + + list += length; + index++; + } + + return -FDT_ERR_NOTFOUND; +} + +static int fdt_get_named_reg(const void *fdt, int node, const char *name, + u64 *start, u64 *size) +{ + int idx; + + idx = __fdt_stringlist_search(fdt, node, "reg-names", name); + if (idx < 0) + return idx; + + return fdt_get_reg(fdt, node, idx, start, size); +} + +static void max10_sensor_uinit(struct intel_max10_device *dev) +{ + struct opae_sensor_info *info; + + TAILQ_FOREACH(info, &dev->opae_sensor_list, node) { + TAILQ_REMOVE(&dev->opae_sensor_list, info, node); + opae_free(info); + } +} + +static bool sensor_reg_valid(struct sensor_reg *reg) +{ + return !!reg->size; +} + +static int max10_add_sensor(struct intel_max10_device *dev, + struct raw_sensor_info *info, struct opae_sensor_info *sensor) +{ + int i; + int ret = 0; + unsigned int val; + + if (!info || !sensor) + return -ENODEV; + + sensor->id = info->id; + sensor->name = info->name; + sensor->type = info->type; + sensor->multiplier = info->multiplier; + + for (i = SENSOR_REG_VALUE; i < SENSOR_REG_MAX; i++) { + if (!sensor_reg_valid(&info->regs[i])) + continue; + + ret = max10_sys_read(dev, info->regs[i].regoff, &val); + if (ret) + break; + + if (val == 0xdeadbeef) { + dev_debug(dev, "%s: sensor:%s invalid 0x%x at:%d\n", + __func__, sensor->name, val, i); + continue; + } + + val *= info->multiplier; + + switch (i) { + case SENSOR_REG_VALUE: + sensor->value_reg = info->regs[i].regoff; + sensor->flags |= OPAE_SENSOR_VALID; + break; + case SENSOR_REG_HIGH_WARN: + sensor->high_warn = val; + sensor->flags |= OPAE_SENSOR_HIGH_WARN_VALID; + break; + case SENSOR_REG_HIGH_FATAL: + sensor->high_fatal = val; + sensor->flags |= OPAE_SENSOR_HIGH_FATAL_VALID; + break; + case SENSOR_REG_LOW_WARN: + sensor->low_warn = val; + sensor->flags |= OPAE_SENSOR_LOW_WARN_VALID; + break; + case SENSOR_REG_LOW_FATAL: + sensor->low_fatal = val; + sensor->flags |= OPAE_SENSOR_LOW_FATAL_VALID; + break; + case SENSOR_REG_HYSTERESIS: + sensor->hysteresis = val; + sensor->flags |= OPAE_SENSOR_HYSTERESIS_VALID; + break; + } + } + + return ret; +} + +static int +max10_sensor_init(struct intel_max10_device *dev, int parent) +{ + int i, ret = 0, offset = 0; + const fdt32_t *num; + const char *ptr; + u64 start, size; + struct raw_sensor_info *raw; + struct opae_sensor_info *sensor; + char *fdt_root = dev->fdt_root; + + if (!fdt_root) { + dev_debug(dev, "skip sensor init as not find Device Tree\n"); + return 0; + } + + fdt_for_each_subnode(offset, fdt_root, parent) { + ptr = fdt_get_name(fdt_root, offset, NULL); + if (!ptr) { + dev_err(dev, "failed to fdt get name\n"); + continue; + } + + if (!strstr(ptr, "sensor")) { + dev_debug(dev, "%s is not a sensor node\n", ptr); + continue; + } + + dev_debug(dev, "found sensor node %s\n", ptr); + + raw = (struct raw_sensor_info *)opae_zmalloc(sizeof(*raw)); + if (!raw) { + ret = -ENOMEM; + goto free_sensor; + } + + raw->name = fdt_getprop(fdt_root, offset, "sensor_name", NULL); + if (!raw->name) { + ret = -EINVAL; + goto free_sensor; + } + + raw->type = fdt_getprop(fdt_root, offset, "type", NULL); + if (!raw->type) { + ret = -EINVAL; + goto free_sensor; + } + + for (i = SENSOR_REG_VALUE; i < SENSOR_REG_MAX; i++) { + ret = fdt_get_named_reg(fdt_root, offset, + sensor_reg_name[i], &start, + &size); + if (ret) { + dev_debug(dev, "no found %d: sensor node %s, %s\n", + ret, ptr, sensor_reg_name[i]); + if (i == SENSOR_REG_VALUE) { + ret = -EINVAL; + goto free_sensor; + } + + continue; + } + + /* This is a hack to compatible with non-secure + * solution. If sensors are included in root node, + * then it's non-secure dtb, which use absolute addr + * of non-secure solution. + */ + if (parent) + raw->regs[i].regoff = start; + else + raw->regs[i].regoff = start - + MAX10_BASE_ADDR; + raw->regs[i].size = size; + } + + num = fdt_getprop(fdt_root, offset, "id", NULL); + if (!num) { + ret = -EINVAL; + goto free_sensor; + } + + raw->id = fdt32_to_cpu(*num); + num = fdt_getprop(fdt_root, offset, "multiplier", NULL); + raw->multiplier = num ? fdt32_to_cpu(*num) : 1; + + dev_debug(dev, "found sensor from DTB: %s: %s: %u: %u\n", + raw->name, raw->type, + raw->id, raw->multiplier); + + for (i = SENSOR_REG_VALUE; i < SENSOR_REG_MAX; i++) + dev_debug(dev, "sensor reg[%d]: %x: %zu\n", + i, raw->regs[i].regoff, + raw->regs[i].size); + + sensor = opae_zmalloc(sizeof(*sensor)); + if (!sensor) { + ret = -EINVAL; + goto free_sensor; + } + + if (max10_add_sensor(dev, raw, sensor)) { + ret = -EINVAL; + opae_free(sensor); + goto free_sensor; + } + + if (sensor->flags & OPAE_SENSOR_VALID) { + TAILQ_INSERT_TAIL(&dev->opae_sensor_list, sensor, node); + dev_info(dev, "found valid sensor: %s\n", sensor->name); + } else + opae_free(sensor); + + opae_free(raw); + } + + return 0; + +free_sensor: + if (raw) + opae_free(raw); + max10_sensor_uinit(dev); + return ret; +} + +static int check_max10_version(struct intel_max10_device *dev) +{ + unsigned int v; + + if (!max10_reg_read(dev, MAX10_SEC_BASE_ADDR + MAX10_BUILD_VER, + &v)) { + if (v != 0xffffffff) { + dev_info(dev, "secure MAX10 detected\n"); + dev->base = MAX10_SEC_BASE_ADDR; + dev->flags |= MAX10_FLAGS_SECURE; + } else { + dev_info(dev, "non-secure MAX10 detected\n"); + dev->base = MAX10_BASE_ADDR; + } + return 0; + } + + return -ENODEV; +} + +static int +max10_secure_hw_init(struct intel_max10_device *dev) +{ + int offset, sysmgr_offset = 0; + char *fdt_root; + + fdt_root = dev->fdt_root; + if (!fdt_root) { + dev_debug(dev, "skip init as not find Device Tree\n"); + return 0; + } + + fdt_for_each_subnode(offset, fdt_root, 0) { + if (!fdt_node_check_compatible(fdt_root, offset, + "intel-max10,system-manager")) { + sysmgr_offset = offset; + break; + } + } + + max10_check_capability(dev); + + max10_sensor_init(dev, sysmgr_offset); + + return 0; +} + +static int +max10_non_secure_hw_init(struct intel_max10_device *dev) +{ + max10_check_capability(dev); + + max10_sensor_init(dev, 0); + + return 0; +} + struct intel_max10_device * intel_max10_device_probe(struct altera_spi_device *spi, int chipselect) @@ -207,6 +574,8 @@ intel_max10_device_probe(struct altera_spi_device *spi, if (!dev) return NULL; + TAILQ_INIT(&dev->opae_sensor_list); + dev->spi_master = spi; dev->spi_tran_dev = spi_transaction_init(spi, chipselect); @@ -215,34 +584,48 @@ intel_max10_device_probe(struct altera_spi_device *spi, goto free_dev; } - /* set the max10 device firstly */ - g_max10 = dev; + /* check the max10 version */ + ret = check_max10_version(dev); + if (ret) { + dev_err(dev, "Failed to find max10 hardware!\n"); + goto free_dev; + } - /* init the MAX10 device table */ + /* load the MAX10 device table */ ret = init_max10_device_table(dev); if (ret) { - dev_err(dev, "init max10 device table fail\n"); + dev_err(dev, "Init max10 device table fail\n"); goto free_dev; } - max10_check_capability(dev); + /* init max10 devices, like sensor*/ + if (dev->flags & MAX10_FLAGS_SECURE) + ret = max10_secure_hw_init(dev); + else + ret = max10_non_secure_hw_init(dev); + if (ret) { + dev_err(dev, "Failed to init max10 hardware!\n"); + goto free_dtb; + } /* read FPGA loading information */ - ret = max10_reg_read(FPGA_PAGE_INFO_OFF, &val); + ret = max10_sys_read(dev, FPGA_PAGE_INFO, &val); if (ret) { dev_err(dev, "fail to get FPGA loading info\n"); - goto spi_tran_fail; + goto release_max10_hw; } dev_info(dev, "FPGA loaded from %s Image\n", val ? "User" : "Factory"); return dev; -spi_tran_fail: +release_max10_hw: + max10_sensor_uinit(dev); +free_dtb: if (dev->fdt_root) opae_free(dev->fdt_root); - spi_transaction_remove(dev->spi_tran_dev); + if (dev->spi_tran_dev) + spi_transaction_remove(dev->spi_tran_dev); free_dev: - g_max10 = NULL; opae_free(dev); return NULL; @@ -253,13 +636,14 @@ int intel_max10_device_remove(struct intel_max10_device *dev) if (!dev) return 0; + max10_sensor_uinit(dev); + if (dev->spi_tran_dev) spi_transaction_remove(dev->spi_tran_dev); if (dev->fdt_root) opae_free(dev->fdt_root); - g_max10 = NULL; opae_free(dev); return 0;