1473c88f9SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 2473c88f9SBruce Richardson * Copyright(c) 2010-2019 Intel Corporation 3473c88f9SBruce Richardson */ 4473c88f9SBruce Richardson 5473c88f9SBruce Richardson #include "opae_intel_max10.h" 6e1defba4STianfei Zhang #include <libfdt.h> 7ca6eb0f7SWei Huang #include "opae_osdep.h" 8473c88f9SBruce Richardson 911986223SStephen Hemminger #ifndef TAILQ_FOREACH_SAFE 1011986223SStephen Hemminger #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ 1111986223SStephen Hemminger for ((var) = TAILQ_FIRST((head)); \ 1211986223SStephen Hemminger (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 1311986223SStephen Hemminger (var) = (tvar)) 1411986223SStephen Hemminger #endif 1511986223SStephen Hemminger 164a19f891STianfei Zhang int max10_sys_read(struct intel_max10_device *dev, 174a19f891STianfei Zhang unsigned int offset, unsigned int *val) 1871da60b8STianfei Zhang { 19ca6eb0f7SWei Huang if (!dev || !dev->ops->reg_read) 2071da60b8STianfei Zhang return -ENODEV; 2171da60b8STianfei Zhang 22ca6eb0f7SWei Huang return dev->ops->reg_read(dev, dev->csr->base + offset, val); 2371da60b8STianfei Zhang } 2471da60b8STianfei Zhang 254a19f891STianfei Zhang int max10_sys_write(struct intel_max10_device *dev, 264a19f891STianfei Zhang unsigned int offset, unsigned int val) 2771da60b8STianfei Zhang { 28ca6eb0f7SWei Huang if (!dev || !dev->ops->reg_write) 2971da60b8STianfei Zhang return -ENODEV; 3071da60b8STianfei Zhang 31ca6eb0f7SWei Huang return dev->ops->reg_write(dev, dev->csr->base + offset, val); 32ca6eb0f7SWei Huang } 33ca6eb0f7SWei Huang 34ca6eb0f7SWei Huang int max10_reg_read(struct intel_max10_device *dev, 35ca6eb0f7SWei Huang unsigned int offset, unsigned int *val) 36ca6eb0f7SWei Huang { 37ca6eb0f7SWei Huang if (!dev || !dev->ops->reg_read) 38ca6eb0f7SWei Huang return -ENODEV; 39ca6eb0f7SWei Huang 40ca6eb0f7SWei Huang return dev->ops->reg_read(dev, offset, val); 41ca6eb0f7SWei Huang } 42ca6eb0f7SWei Huang 43ca6eb0f7SWei Huang int max10_reg_write(struct intel_max10_device *dev, 44ca6eb0f7SWei Huang unsigned int offset, unsigned int val) 45ca6eb0f7SWei Huang { 46ca6eb0f7SWei Huang if (!dev || !dev->ops->reg_write) 47ca6eb0f7SWei Huang return -ENODEV; 48ca6eb0f7SWei Huang 49ca6eb0f7SWei Huang return dev->ops->reg_write(dev, offset, val); 5071da60b8STianfei Zhang } 5171da60b8STianfei Zhang 52a05bd1b4SWei Huang int max10_sys_update_bits(struct intel_max10_device *dev, unsigned int offset, 53a05bd1b4SWei Huang unsigned int msk, unsigned int val) 54a05bd1b4SWei Huang { 55a05bd1b4SWei Huang int ret = 0; 56a05bd1b4SWei Huang unsigned int temp = 0; 57a05bd1b4SWei Huang 58a05bd1b4SWei Huang ret = max10_sys_read(dev, offset, &temp); 59a05bd1b4SWei Huang if (ret < 0) 60a05bd1b4SWei Huang return ret; 61a05bd1b4SWei Huang 62a05bd1b4SWei Huang temp &= ~msk; 63a05bd1b4SWei Huang temp |= val & msk; 64a05bd1b4SWei Huang 65a05bd1b4SWei Huang return max10_sys_write(dev, offset, temp); 66a05bd1b4SWei Huang } 67a05bd1b4SWei Huang 68b74ee6c8SWei Huang static int n3000_bulk_raw_write(struct intel_max10_device *dev, uint32_t addr, 69b74ee6c8SWei Huang void *buf, uint32_t len) 70b74ee6c8SWei Huang { 71b74ee6c8SWei Huang uint32_t v = 0; 72b74ee6c8SWei Huang uint32_t i = 0; 73b74ee6c8SWei Huang char *p = buf; 74b74ee6c8SWei Huang int ret = 0; 75b74ee6c8SWei Huang 76b74ee6c8SWei Huang len = IFPGA_ALIGN(len, 4); 77b74ee6c8SWei Huang 78b74ee6c8SWei Huang for (i = 0; i < len; i += 4) { 79b74ee6c8SWei Huang v = *(uint32_t *)(p + i); 80b74ee6c8SWei Huang ret = max10_reg_write(dev, addr + i, v); 81b74ee6c8SWei Huang if (ret < 0) { 82b74ee6c8SWei Huang dev_err(dev, 83b74ee6c8SWei Huang "Failed to write to staging area 0x%08x [e:%d]\n", 84b74ee6c8SWei Huang addr + i, ret); 85b74ee6c8SWei Huang return ret; 86b74ee6c8SWei Huang } 87b74ee6c8SWei Huang } 88b74ee6c8SWei Huang 89b74ee6c8SWei Huang return 0; 90b74ee6c8SWei Huang } 91b74ee6c8SWei Huang 92b74ee6c8SWei Huang static int n3000_bulk_raw_read(struct intel_max10_device *dev, 93b74ee6c8SWei Huang uint32_t addr, void *buf, uint32_t len) 94b74ee6c8SWei Huang { 95b74ee6c8SWei Huang u32 v, i; 96b74ee6c8SWei Huang char *p = buf; 97b74ee6c8SWei Huang int ret; 98b74ee6c8SWei Huang 99b74ee6c8SWei Huang len = IFPGA_ALIGN(len, 4); 100b74ee6c8SWei Huang 101b74ee6c8SWei Huang for (i = 0; i < len; i += 4) { 102b74ee6c8SWei Huang ret = max10_reg_read(dev, addr + i, &v); 103b74ee6c8SWei Huang if (ret < 0) { 104b74ee6c8SWei Huang dev_err(dev, 105b74ee6c8SWei Huang "Failed to write to staging area 0x%08x [e:%d]\n", 106b74ee6c8SWei Huang addr + i, ret); 107b74ee6c8SWei Huang return ret; 108b74ee6c8SWei Huang } 109b74ee6c8SWei Huang *(u32 *)(p + i) = v; 110b74ee6c8SWei Huang } 111b74ee6c8SWei Huang 112b74ee6c8SWei Huang return 0; 113b74ee6c8SWei Huang } 114b74ee6c8SWei Huang 115b74ee6c8SWei Huang static int n3000_flash_read(struct intel_max10_device *dev, 116b74ee6c8SWei Huang u32 addr, void *buf, u32 size) 117b74ee6c8SWei Huang { 118b74ee6c8SWei Huang if (!dev->raw_blk_ops.read_blk) 119b74ee6c8SWei Huang return -ENODEV; 120b74ee6c8SWei Huang 121b74ee6c8SWei Huang return dev->raw_blk_ops.read_blk(dev, addr, buf, size); 122b74ee6c8SWei Huang } 123b74ee6c8SWei Huang 124b74ee6c8SWei Huang static int n3000_flash_write(struct intel_max10_device *dev, 125b74ee6c8SWei Huang u32 addr, void *buf, u32 size) 126b74ee6c8SWei Huang { 127b74ee6c8SWei Huang if (!dev->raw_blk_ops.write_blk) 128b74ee6c8SWei Huang return -ENODEV; 129b74ee6c8SWei Huang 130b74ee6c8SWei Huang return dev->raw_blk_ops.write_blk(dev, addr, buf, size); 131b74ee6c8SWei Huang } 132b74ee6c8SWei Huang 133b74ee6c8SWei Huang static u32 134b74ee6c8SWei Huang pmci_get_write_space(struct intel_max10_device *dev, u32 size) 135b74ee6c8SWei Huang { 136b74ee6c8SWei Huang u32 count, val; 137b74ee6c8SWei Huang int ret; 138b74ee6c8SWei Huang 139b74ee6c8SWei Huang ret = opae_readl_poll_timeout(dev->mmio + PMCI_FLASH_CTRL, val, 140b74ee6c8SWei Huang GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) == 141b74ee6c8SWei Huang PMCI_FIFO_MAX_WORDS, 142b74ee6c8SWei Huang PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US); 143b74ee6c8SWei Huang if (ret == -ETIMEDOUT) 144b74ee6c8SWei Huang return 0; 145b74ee6c8SWei Huang 146b74ee6c8SWei Huang count = GET_FIELD(PMCI_FLASH_FIFO_SPACE, val) * 4; 147b74ee6c8SWei Huang 148b74ee6c8SWei Huang return (size > count) ? count : size; 149b74ee6c8SWei Huang } 150b74ee6c8SWei Huang 151b74ee6c8SWei Huang static void pmci_write_fifo(void __iomem *base, char *buf, size_t count) 152b74ee6c8SWei Huang { 153b74ee6c8SWei Huang size_t i; 154b74ee6c8SWei Huang u32 val; 155b74ee6c8SWei Huang 156b74ee6c8SWei Huang for (i = 0; i < count/4 ; i++) { 157b74ee6c8SWei Huang val = *(u32 *)(buf + i * 4); 158b74ee6c8SWei Huang writel(val, base); 159b74ee6c8SWei Huang } 160b74ee6c8SWei Huang } 161b74ee6c8SWei Huang 162b74ee6c8SWei Huang static void pmci_read_fifo(void __iomem *base, char *buf, size_t count) 163b74ee6c8SWei Huang { 164b74ee6c8SWei Huang size_t i; 165b74ee6c8SWei Huang u32 val; 166b74ee6c8SWei Huang 167b74ee6c8SWei Huang for (i = 0; i < count/4; i++) { 168b74ee6c8SWei Huang val = readl(base); 169b74ee6c8SWei Huang *(u32 *)(buf + i * 4) = val; 170b74ee6c8SWei Huang } 171b74ee6c8SWei Huang } 172b74ee6c8SWei Huang 173b74ee6c8SWei Huang static int 174b74ee6c8SWei Huang __pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr, 175b74ee6c8SWei Huang void *buf, u32 size) 176b74ee6c8SWei Huang { 177b74ee6c8SWei Huang UNUSED(addr); 178b74ee6c8SWei Huang u32 blk_size, n_offset = 0; 179b74ee6c8SWei Huang 180b74ee6c8SWei Huang while (size) { 181b74ee6c8SWei Huang blk_size = pmci_get_write_space(dev, size); 182b74ee6c8SWei Huang if (blk_size == 0) { 183b74ee6c8SWei Huang dev_err(pmci->dev, "get FIFO available size fail\n"); 184b74ee6c8SWei Huang return -EIO; 185b74ee6c8SWei Huang } 186b74ee6c8SWei Huang size -= blk_size; 187b74ee6c8SWei Huang pmci_write_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + n_offset, 188b74ee6c8SWei Huang blk_size); 189b74ee6c8SWei Huang n_offset += blk_size; 190b74ee6c8SWei Huang } 191b74ee6c8SWei Huang 192b74ee6c8SWei Huang return 0; 193b74ee6c8SWei Huang } 194b74ee6c8SWei Huang 195b74ee6c8SWei Huang static int 196b74ee6c8SWei Huang pmci_flash_bulk_write(struct intel_max10_device *dev, u32 addr, 197b74ee6c8SWei Huang void *buf, u32 size) 198b74ee6c8SWei Huang { 199b74ee6c8SWei Huang int ret; 200b74ee6c8SWei Huang 201b74ee6c8SWei Huang pthread_mutex_lock(dev->bmc_ops.mutex); 202b74ee6c8SWei Huang 203b74ee6c8SWei Huang ret = __pmci_flash_bulk_write(dev, addr, buf, size); 204b74ee6c8SWei Huang 205b74ee6c8SWei Huang pthread_mutex_unlock(dev->bmc_ops.mutex); 206b74ee6c8SWei Huang return ret; 207b74ee6c8SWei Huang } 208b74ee6c8SWei Huang 209b74ee6c8SWei Huang static int 210b74ee6c8SWei Huang pmci_set_flash_host_mux(struct intel_max10_device *dev, bool request) 211b74ee6c8SWei Huang { 212b74ee6c8SWei Huang u32 ctrl; 213b74ee6c8SWei Huang int ret; 214b74ee6c8SWei Huang 215b74ee6c8SWei Huang ret = max10_sys_update_bits(dev, 216b74ee6c8SWei Huang m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL, 217b74ee6c8SWei Huang FLASH_HOST_REQUEST, 218b74ee6c8SWei Huang SET_FIELD(FLASH_HOST_REQUEST, request)); 219b74ee6c8SWei Huang if (ret) 220b74ee6c8SWei Huang return ret; 221b74ee6c8SWei Huang 222b74ee6c8SWei Huang return opae_max10_read_poll_timeout(dev, m10bmc_base(dev) + M10BMC_PMCI_FLASH_CTRL, 223b74ee6c8SWei Huang ctrl, request ? (get_flash_mux(ctrl) == FLASH_MUX_HOST) : 224b74ee6c8SWei Huang (get_flash_mux(ctrl) != FLASH_MUX_HOST), 225b74ee6c8SWei Huang PMCI_FLASH_INT_US, PMCI_FLASH_TIMEOUT_US); 226b74ee6c8SWei Huang } 227b74ee6c8SWei Huang 228b74ee6c8SWei Huang static int 229b74ee6c8SWei Huang pmci_get_mux(struct intel_max10_device *dev) 230b74ee6c8SWei Huang { 231b74ee6c8SWei Huang pthread_mutex_lock(dev->bmc_ops.mutex); 232b74ee6c8SWei Huang return pmci_set_flash_host_mux(dev, true); 233b74ee6c8SWei Huang } 234b74ee6c8SWei Huang 235b74ee6c8SWei Huang static int 236b74ee6c8SWei Huang pmci_put_mux(struct intel_max10_device *dev) 237b74ee6c8SWei Huang { 238b74ee6c8SWei Huang int ret; 239b74ee6c8SWei Huang 240b74ee6c8SWei Huang ret = pmci_set_flash_host_mux(dev, false); 241b74ee6c8SWei Huang pthread_mutex_unlock(dev->bmc_ops.mutex); 242b74ee6c8SWei Huang return ret; 243b74ee6c8SWei Huang } 244b74ee6c8SWei Huang 245b74ee6c8SWei Huang static int 246b74ee6c8SWei Huang __pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr, 247b74ee6c8SWei Huang void *buf, u32 size) 248b74ee6c8SWei Huang { 249b74ee6c8SWei Huang u32 blk_size, offset = 0, val; 250b74ee6c8SWei Huang int ret; 251b74ee6c8SWei Huang 252b74ee6c8SWei Huang while (size) { 253b74ee6c8SWei Huang blk_size = min_t(u32, size, PMCI_READ_BLOCK_SIZE); 254b74ee6c8SWei Huang 255b74ee6c8SWei Huang opae_writel(addr + offset, dev->mmio + PMCI_FLASH_ADDR); 256b74ee6c8SWei Huang 257b74ee6c8SWei Huang opae_writel(SET_FIELD(PMCI_FLASH_READ_COUNT, blk_size / 4) 258b74ee6c8SWei Huang | PMCI_FLASH_RD_MODE, 259b74ee6c8SWei Huang dev->mmio + PMCI_FLASH_CTRL); 260b74ee6c8SWei Huang 261b74ee6c8SWei Huang ret = opae_readl_poll_timeout((dev->mmio + PMCI_FLASH_CTRL), 262b74ee6c8SWei Huang val, !(val & PMCI_FLASH_BUSY), 263b74ee6c8SWei Huang PMCI_FLASH_INT_US, 264b74ee6c8SWei Huang PMCI_FLASH_TIMEOUT_US); 265b74ee6c8SWei Huang if (ret) { 266b74ee6c8SWei Huang dev_err(dev, "%s timed out on reading flash 0x%xn", 267b74ee6c8SWei Huang __func__, val); 268b74ee6c8SWei Huang return ret; 269b74ee6c8SWei Huang } 270b74ee6c8SWei Huang 271b74ee6c8SWei Huang pmci_read_fifo(dev->mmio + PMCI_FLASH_FIFO, (char *)buf + offset, 272b74ee6c8SWei Huang blk_size); 273b74ee6c8SWei Huang 274b74ee6c8SWei Huang size -= blk_size; 275b74ee6c8SWei Huang offset += blk_size; 276b74ee6c8SWei Huang 277b74ee6c8SWei Huang opae_writel(0, dev->mmio + PMCI_FLASH_CTRL); 278b74ee6c8SWei Huang } 279b74ee6c8SWei Huang 280b74ee6c8SWei Huang return 0; 281b74ee6c8SWei Huang } 282b74ee6c8SWei Huang 283b74ee6c8SWei Huang static int 284b74ee6c8SWei Huang pmci_flash_bulk_read(struct intel_max10_device *dev, u32 addr, 285b74ee6c8SWei Huang void *buf, u32 size) 286b74ee6c8SWei Huang { 287b74ee6c8SWei Huang int ret; 288b74ee6c8SWei Huang 289b74ee6c8SWei Huang ret = pmci_get_mux(dev); 290b74ee6c8SWei Huang if (ret) 291b74ee6c8SWei Huang goto fail; 292b74ee6c8SWei Huang 293b74ee6c8SWei Huang ret = __pmci_flash_bulk_read(dev, addr, buf, size); 294b74ee6c8SWei Huang if (ret) 295b74ee6c8SWei Huang goto fail; 296b74ee6c8SWei Huang 297b74ee6c8SWei Huang return pmci_put_mux(dev); 298b74ee6c8SWei Huang 299b74ee6c8SWei Huang fail: 300b74ee6c8SWei Huang pmci_put_mux(dev); 301b74ee6c8SWei Huang return ret; 302b74ee6c8SWei Huang } 303b74ee6c8SWei Huang 304b74ee6c8SWei Huang static int pmci_check_flash_address(u32 start, u32 end) 305b74ee6c8SWei Huang { 306b74ee6c8SWei Huang if (start < PMCI_FLASH_START || end > PMCI_FLASH_END) 307b74ee6c8SWei Huang return -EINVAL; 308b74ee6c8SWei Huang 309b74ee6c8SWei Huang return 0; 310b74ee6c8SWei Huang } 311b74ee6c8SWei Huang 312b74ee6c8SWei Huang int opae_read_flash(struct intel_max10_device *dev, u32 addr, 313b74ee6c8SWei Huang u32 size, void *buf) 314b74ee6c8SWei Huang { 315b74ee6c8SWei Huang int ret; 316b74ee6c8SWei Huang 317b74ee6c8SWei Huang if (!dev->bmc_ops.flash_read) 318b74ee6c8SWei Huang return -ENODEV; 319b74ee6c8SWei Huang 320b74ee6c8SWei Huang if (!buf) 321b74ee6c8SWei Huang return -EINVAL; 322b74ee6c8SWei Huang 323b74ee6c8SWei Huang if (dev->bmc_ops.check_flash_range) { 324b74ee6c8SWei Huang ret = dev->bmc_ops.check_flash_range(addr, addr + size); 325b74ee6c8SWei Huang if (ret) 326b74ee6c8SWei Huang return ret; 327b74ee6c8SWei Huang } else { 328b74ee6c8SWei Huang u32 top_addr = dev->staging_area_base + dev->staging_area_size; 329b74ee6c8SWei Huang if ((addr < dev->staging_area_base) || 330b74ee6c8SWei Huang ((addr + size) >= top_addr)) 331b74ee6c8SWei Huang return -EINVAL; 332b74ee6c8SWei Huang } 333b74ee6c8SWei Huang 334b74ee6c8SWei Huang ret = dev->bmc_ops.flash_read(dev, addr, buf, size); 335b74ee6c8SWei Huang if (ret) 336b74ee6c8SWei Huang return ret; 337b74ee6c8SWei Huang 338b74ee6c8SWei Huang return 0; 339b74ee6c8SWei Huang } 340b74ee6c8SWei Huang 341ca6eb0f7SWei Huang static int max10_spi_read(struct intel_max10_device *dev, 342ca6eb0f7SWei Huang unsigned int addr, unsigned int *val) 343ca6eb0f7SWei Huang { 344ca6eb0f7SWei Huang if (!dev) 345ca6eb0f7SWei Huang return -ENODEV; 346ca6eb0f7SWei Huang 347ca6eb0f7SWei Huang dev_debug(dev, "%s: bus:0x%x, addr:0x%x\n", __func__, dev->bus, addr); 348ca6eb0f7SWei Huang 349ca6eb0f7SWei Huang return spi_transaction_read(dev->spi_tran_dev, 350ca6eb0f7SWei Huang addr, 4, (unsigned char *)val); 351ca6eb0f7SWei Huang } 352ca6eb0f7SWei Huang 353ca6eb0f7SWei Huang static int max10_spi_write(struct intel_max10_device *dev, 354ca6eb0f7SWei Huang unsigned int addr, unsigned int val) 355ca6eb0f7SWei Huang { 356ca6eb0f7SWei Huang unsigned int tmp = val; 357ca6eb0f7SWei Huang 358ca6eb0f7SWei Huang if (!dev) 359ca6eb0f7SWei Huang return -ENODEV; 360ca6eb0f7SWei Huang 361ca6eb0f7SWei Huang dev_debug(dev, "%s: bus:0x%x, reg:0x%x, val:0x%x\n", __func__, 362ca6eb0f7SWei Huang dev->bus, addr, val); 363ca6eb0f7SWei Huang 364ca6eb0f7SWei Huang return spi_transaction_write(dev->spi_tran_dev, 365ca6eb0f7SWei Huang addr, 4, (unsigned char *)&tmp); 366ca6eb0f7SWei Huang } 367ca6eb0f7SWei Huang 368ca6eb0f7SWei Huang static int indirect_bus_clr_cmd(struct intel_max10_device *dev) 369ca6eb0f7SWei Huang { 370ca6eb0f7SWei Huang unsigned int cmd; 371ca6eb0f7SWei Huang int ret; 372ca6eb0f7SWei Huang 373ca6eb0f7SWei Huang opae_writel(0, dev->mmio + INDIRECT_CMD_OFF); 374ca6eb0f7SWei Huang 375ca6eb0f7SWei Huang ret = opae_readl_poll_timeout((dev->mmio + INDIRECT_CMD_OFF), cmd, 376ca6eb0f7SWei Huang (!cmd), INDIRECT_INT_US, INDIRECT_TIMEOUT_US); 377ca6eb0f7SWei Huang 378ca6eb0f7SWei Huang if (ret) 379ca6eb0f7SWei Huang dev_err(dev, "%s timed out on clearing cmd 0x%x\n", 380ca6eb0f7SWei Huang __func__, cmd); 381ca6eb0f7SWei Huang 382ca6eb0f7SWei Huang return ret; 383ca6eb0f7SWei Huang } 384ca6eb0f7SWei Huang 385ca6eb0f7SWei Huang static int max10_indirect_reg_read(struct intel_max10_device *dev, 386ca6eb0f7SWei Huang unsigned int addr, unsigned int *val) 387ca6eb0f7SWei Huang { 388ca6eb0f7SWei Huang unsigned int cmd; 389ca6eb0f7SWei Huang int ret; 390ca6eb0f7SWei Huang 391ca6eb0f7SWei Huang if (!dev) 392ca6eb0f7SWei Huang return -ENODEV; 393ca6eb0f7SWei Huang 394ca6eb0f7SWei Huang pthread_mutex_lock(dev->bmc_ops.mutex); 395ca6eb0f7SWei Huang 396ca6eb0f7SWei Huang cmd = opae_readl(dev->mmio + INDIRECT_CMD_OFF); 397ca6eb0f7SWei Huang if (cmd) 398ca6eb0f7SWei Huang dev_warn(dev, "%s non-zero cmd 0x%x\n", __func__, cmd); 399ca6eb0f7SWei Huang 400ca6eb0f7SWei Huang opae_writel(addr, dev->mmio + INDIRECT_ADDR_OFF); 401ca6eb0f7SWei Huang 402ca6eb0f7SWei Huang opae_writel(INDIRECT_CMD_RD, dev->mmio + INDIRECT_CMD_OFF); 403ca6eb0f7SWei Huang 404ca6eb0f7SWei Huang ret = opae_readl_poll_timeout((dev->mmio + INDIRECT_CMD_OFF), cmd, 405ca6eb0f7SWei Huang (cmd & INDIRECT_CMD_ACK), INDIRECT_INT_US, 406ca6eb0f7SWei Huang INDIRECT_TIMEOUT_US); 407ca6eb0f7SWei Huang 408ca6eb0f7SWei Huang *val = opae_readl(dev->mmio + INDIRECT_RD_OFF); 409ca6eb0f7SWei Huang 410ca6eb0f7SWei Huang if (ret) 411ca6eb0f7SWei Huang dev_err(dev, "%s timed out on reg 0x%x cmd 0x%x\n", 412ca6eb0f7SWei Huang __func__, addr, cmd); 413ca6eb0f7SWei Huang 414ca6eb0f7SWei Huang if (indirect_bus_clr_cmd(dev)) 415ca6eb0f7SWei Huang ret = -ETIME; 416ca6eb0f7SWei Huang 417ca6eb0f7SWei Huang pthread_mutex_unlock(dev->bmc_ops.mutex); 418ca6eb0f7SWei Huang 419ca6eb0f7SWei Huang return ret; 420ca6eb0f7SWei Huang } 421ca6eb0f7SWei Huang 422ca6eb0f7SWei Huang static int max10_indirect_reg_write(struct intel_max10_device *dev, 423ca6eb0f7SWei Huang unsigned int addr, unsigned int val) 424ca6eb0f7SWei Huang { 425ca6eb0f7SWei Huang unsigned int cmd; 426ca6eb0f7SWei Huang int ret; 427ca6eb0f7SWei Huang 428ca6eb0f7SWei Huang if (!dev) 429ca6eb0f7SWei Huang return -ENODEV; 430ca6eb0f7SWei Huang 431ca6eb0f7SWei Huang pthread_mutex_lock(dev->bmc_ops.mutex); 432ca6eb0f7SWei Huang 433ca6eb0f7SWei Huang cmd = readl(dev->mmio + INDIRECT_CMD_OFF); 434ca6eb0f7SWei Huang 435ca6eb0f7SWei Huang if (cmd) 436ca6eb0f7SWei Huang dev_warn(dev, "%s non-zero cmd 0x%x\n", __func__, cmd); 437ca6eb0f7SWei Huang 438ca6eb0f7SWei Huang opae_writel(val, dev->mmio + INDIRECT_WR_OFF); 439ca6eb0f7SWei Huang 440ca6eb0f7SWei Huang opae_writel(addr, dev->mmio + INDIRECT_ADDR_OFF); 441ca6eb0f7SWei Huang 442ca6eb0f7SWei Huang writel(INDIRECT_CMD_WR, dev->mmio + INDIRECT_CMD_OFF); 443ca6eb0f7SWei Huang 444ca6eb0f7SWei Huang ret = opae_readl_poll_timeout((dev->mmio + INDIRECT_CMD_OFF), cmd, 445ca6eb0f7SWei Huang (cmd & INDIRECT_CMD_ACK), INDIRECT_INT_US, 446ca6eb0f7SWei Huang INDIRECT_TIMEOUT_US); 447ca6eb0f7SWei Huang 448ca6eb0f7SWei Huang if (ret) 449ca6eb0f7SWei Huang dev_err(dev, "%s timed out on reg 0x%x cmd 0x%x\n", 450ca6eb0f7SWei Huang __func__, addr, cmd); 451ca6eb0f7SWei Huang 452ca6eb0f7SWei Huang if (indirect_bus_clr_cmd(dev)) 453ca6eb0f7SWei Huang ret = -ETIME; 454ca6eb0f7SWei Huang 455ca6eb0f7SWei Huang pthread_mutex_unlock(dev->bmc_ops.mutex); 456ca6eb0f7SWei Huang 457ca6eb0f7SWei Huang return ret; 458ca6eb0f7SWei Huang } 459ca6eb0f7SWei Huang 460ca6eb0f7SWei Huang const struct m10bmc_regmap m10bmc_pmci_regmap = { 461ca6eb0f7SWei Huang .reg_write = max10_indirect_reg_write, 462ca6eb0f7SWei Huang .reg_read = max10_indirect_reg_read, 463ca6eb0f7SWei Huang }; 464ca6eb0f7SWei Huang 465ca6eb0f7SWei Huang const struct m10bmc_regmap m10bmc_n3000_regmap = { 466ca6eb0f7SWei Huang .reg_write = max10_spi_write, 467ca6eb0f7SWei Huang .reg_read = max10_spi_read, 468ca6eb0f7SWei Huang }; 469ca6eb0f7SWei Huang 470e1defba4STianfei Zhang static struct max10_compatible_id max10_id_table[] = { 471e1defba4STianfei Zhang {.compatible = MAX10_PAC,}, 472e1defba4STianfei Zhang {.compatible = MAX10_PAC_N3000,}, 473e1defba4STianfei Zhang {.compatible = MAX10_PAC_END,} 474e1defba4STianfei Zhang }; 475e1defba4STianfei Zhang 476e1defba4STianfei Zhang static struct max10_compatible_id *max10_match_compatible(const char *fdt_root) 477e1defba4STianfei Zhang { 478e1defba4STianfei Zhang struct max10_compatible_id *id = max10_id_table; 479e1defba4STianfei Zhang 480e1defba4STianfei Zhang for (; strcmp(id->compatible, MAX10_PAC_END); id++) { 481e1defba4STianfei Zhang if (fdt_node_check_compatible(fdt_root, 0, id->compatible)) 482e1defba4STianfei Zhang continue; 483e1defba4STianfei Zhang 484e1defba4STianfei Zhang return id; 485e1defba4STianfei Zhang } 486e1defba4STianfei Zhang 487e1defba4STianfei Zhang return NULL; 488e1defba4STianfei Zhang } 489e1defba4STianfei Zhang 490e1defba4STianfei Zhang static inline bool 491e1defba4STianfei Zhang is_max10_pac_n3000(struct intel_max10_device *max10) 492e1defba4STianfei Zhang { 493e1defba4STianfei Zhang return max10->id && !strcmp(max10->id->compatible, 494e1defba4STianfei Zhang MAX10_PAC_N3000); 495e1defba4STianfei Zhang } 496e1defba4STianfei Zhang 497e1defba4STianfei Zhang static void max10_check_capability(struct intel_max10_device *max10) 498e1defba4STianfei Zhang { 499e1defba4STianfei Zhang if (!max10->fdt_root) 500e1defba4STianfei Zhang return; 501e1defba4STianfei Zhang 502e1defba4STianfei Zhang if (is_max10_pac_n3000(max10)) { 503e1defba4STianfei Zhang max10->flags |= MAX10_FLAGS_NO_I2C2 | 504e1defba4STianfei Zhang MAX10_FLAGS_NO_BMCIMG_FLASH; 505e1defba4STianfei Zhang dev_info(max10, "found %s card\n", max10->id->compatible); 50671da60b8STianfei Zhang } else 50771da60b8STianfei Zhang max10->flags |= MAX10_FLAGS_MAC_CACHE; 508e1defba4STianfei Zhang } 509e1defba4STianfei Zhang 5104a19f891STianfei Zhang static int altera_nor_flash_read(struct intel_max10_device *dev, 5114a19f891STianfei Zhang u32 offset, void *buffer, u32 len) 512e1defba4STianfei Zhang { 513e1defba4STianfei Zhang int word_len; 514e1defba4STianfei Zhang int i; 515e1defba4STianfei Zhang unsigned int *buf = (unsigned int *)buffer; 516e1defba4STianfei Zhang unsigned int value; 517e1defba4STianfei Zhang int ret; 518e1defba4STianfei Zhang 5194a19f891STianfei Zhang if (!dev || !buffer || len <= 0) 520e1defba4STianfei Zhang return -ENODEV; 521e1defba4STianfei Zhang 522e1defba4STianfei Zhang word_len = len/4; 523e1defba4STianfei Zhang 524e1defba4STianfei Zhang for (i = 0; i < word_len; i++) { 5254a19f891STianfei Zhang ret = max10_reg_read(dev, offset + i*4, 526e1defba4STianfei Zhang &value); 527e1defba4STianfei Zhang if (ret) 528e1defba4STianfei Zhang return -EBUSY; 529e1defba4STianfei Zhang 530e1defba4STianfei Zhang *buf++ = value; 531e1defba4STianfei Zhang } 532e1defba4STianfei Zhang 533e1defba4STianfei Zhang return 0; 534e1defba4STianfei Zhang } 535e1defba4STianfei Zhang 5364a19f891STianfei Zhang static int enable_nor_flash(struct intel_max10_device *dev, bool on) 537e1defba4STianfei Zhang { 538e1defba4STianfei Zhang unsigned int val = 0; 539e1defba4STianfei Zhang int ret; 540e1defba4STianfei Zhang 5414a19f891STianfei Zhang ret = max10_sys_read(dev, RSU_REG, &val); 542e1defba4STianfei Zhang if (ret) { 543e1defba4STianfei Zhang dev_err(NULL "enabling flash error\n"); 544e1defba4STianfei Zhang return ret; 545e1defba4STianfei Zhang } 546e1defba4STianfei Zhang 547e1defba4STianfei Zhang if (on) 548e1defba4STianfei Zhang val |= RSU_ENABLE; 549e1defba4STianfei Zhang else 550e1defba4STianfei Zhang val &= ~RSU_ENABLE; 551e1defba4STianfei Zhang 5524a19f891STianfei Zhang return max10_sys_write(dev, RSU_REG, val); 553e1defba4STianfei Zhang } 554e1defba4STianfei Zhang 555e1defba4STianfei Zhang static int init_max10_device_table(struct intel_max10_device *max10) 556e1defba4STianfei Zhang { 557e41856b5SWei Huang struct altera_spi_device *spi = NULL; 558e1defba4STianfei Zhang struct max10_compatible_id *id; 559e1defba4STianfei Zhang struct fdt_header hdr; 560e1defba4STianfei Zhang char *fdt_root = NULL; 561e41856b5SWei Huang u32 dtb_magic = 0; 562e1defba4STianfei Zhang u32 dt_size, dt_addr, val; 563e41856b5SWei Huang int ret = 0; 564e1defba4STianfei Zhang 565e41856b5SWei Huang spi = (struct altera_spi_device *)max10->spi_master; 566e41856b5SWei Huang if (!spi) { 567e41856b5SWei Huang dev_err(max10, "spi master is not set\n"); 568e41856b5SWei Huang return -EINVAL; 569e41856b5SWei Huang } 570e41856b5SWei Huang if (spi->dtb) 571e41856b5SWei Huang dtb_magic = *(u32 *)spi->dtb; 572e41856b5SWei Huang 573e41856b5SWei Huang if (dtb_magic != 0xEDFE0DD0) { 574e41856b5SWei Huang dev_info(max10, "read DTB from NOR flash\n"); 5754a19f891STianfei Zhang ret = max10_sys_read(max10, DT_AVAIL_REG, &val); 576e1defba4STianfei Zhang if (ret) { 577e1defba4STianfei Zhang dev_err(max10 "cannot read DT_AVAIL_REG\n"); 578e1defba4STianfei Zhang return ret; 579e1defba4STianfei Zhang } 580e1defba4STianfei Zhang 581e1defba4STianfei Zhang if (!(val & DT_AVAIL)) { 582e1defba4STianfei Zhang dev_err(max10 "DT not available\n"); 583e1defba4STianfei Zhang return -EINVAL; 584e1defba4STianfei Zhang } 585e1defba4STianfei Zhang 5864a19f891STianfei Zhang ret = max10_sys_read(max10, DT_BASE_ADDR_REG, &dt_addr); 587e1defba4STianfei Zhang if (ret) { 588e1defba4STianfei Zhang dev_info(max10 "cannot get base addr of device table\n"); 589e1defba4STianfei Zhang return ret; 590e1defba4STianfei Zhang } 591e1defba4STianfei Zhang 5924a19f891STianfei Zhang ret = enable_nor_flash(max10, true); 593e1defba4STianfei Zhang if (ret) { 594e1defba4STianfei Zhang dev_err(max10 "fail to enable flash\n"); 595e1defba4STianfei Zhang return ret; 596e1defba4STianfei Zhang } 597e1defba4STianfei Zhang 5984a19f891STianfei Zhang ret = altera_nor_flash_read(max10, dt_addr, &hdr, sizeof(hdr)); 599e1defba4STianfei Zhang if (ret) { 600e1defba4STianfei Zhang dev_err(max10 "read fdt header fail\n"); 601e41856b5SWei Huang goto disable_nor_flash; 602e1defba4STianfei Zhang } 603e1defba4STianfei Zhang 604e1defba4STianfei Zhang ret = fdt_check_header(&hdr); 605e1defba4STianfei Zhang if (ret) { 606e1defba4STianfei Zhang dev_err(max10 "check fdt header fail\n"); 607e41856b5SWei Huang goto disable_nor_flash; 608e1defba4STianfei Zhang } 609e1defba4STianfei Zhang 610e1defba4STianfei Zhang dt_size = fdt_totalsize(&hdr); 611e1defba4STianfei Zhang if (dt_size > DFT_MAX_SIZE) { 612e1defba4STianfei Zhang dev_err(max10 "invalid device table size\n"); 613e1defba4STianfei Zhang ret = -EINVAL; 614e41856b5SWei Huang goto disable_nor_flash; 615e1defba4STianfei Zhang } 616e1defba4STianfei Zhang 617e1defba4STianfei Zhang fdt_root = opae_malloc(dt_size); 618e1defba4STianfei Zhang if (!fdt_root) { 619e1defba4STianfei Zhang ret = -ENOMEM; 620e41856b5SWei Huang goto disable_nor_flash; 621e1defba4STianfei Zhang } 622e1defba4STianfei Zhang 6234a19f891STianfei Zhang ret = altera_nor_flash_read(max10, dt_addr, fdt_root, dt_size); 624e1defba4STianfei Zhang if (ret) { 625e41856b5SWei Huang opae_free(fdt_root); 626e41856b5SWei Huang fdt_root = NULL; 627e1defba4STianfei Zhang dev_err(max10 "cannot read device table\n"); 628e41856b5SWei Huang goto disable_nor_flash; 629e1defba4STianfei Zhang } 630e1defba4STianfei Zhang 631e41856b5SWei Huang if (spi->dtb) { 632e41856b5SWei Huang if (*spi->dtb_sz_ptr < dt_size) { 633e41856b5SWei Huang dev_warn(max10, 634e41856b5SWei Huang "share memory for dtb is smaller than required %u\n", 635e41856b5SWei Huang dt_size); 636e41856b5SWei Huang } else { 637e41856b5SWei Huang *spi->dtb_sz_ptr = dt_size; 638e41856b5SWei Huang } 639e41856b5SWei Huang /* store dtb data into share memory */ 640e41856b5SWei Huang memcpy(spi->dtb, fdt_root, *spi->dtb_sz_ptr); 641e41856b5SWei Huang } 642e41856b5SWei Huang 643e41856b5SWei Huang disable_nor_flash: 644e41856b5SWei Huang enable_nor_flash(max10, false); 645e41856b5SWei Huang } else { 646e41856b5SWei Huang if (*spi->dtb_sz_ptr > 0) { 647e41856b5SWei Huang dev_info(max10, "read DTB from shared memory\n"); 648e41856b5SWei Huang fdt_root = opae_malloc(*spi->dtb_sz_ptr); 649e41856b5SWei Huang if (fdt_root) 650e41856b5SWei Huang memcpy(fdt_root, spi->dtb, *spi->dtb_sz_ptr); 651e41856b5SWei Huang else 652e41856b5SWei Huang ret = -ENOMEM; 653e41856b5SWei Huang } 654e41856b5SWei Huang } 655e41856b5SWei Huang 656e41856b5SWei Huang if (fdt_root) { 657e1defba4STianfei Zhang id = max10_match_compatible(fdt_root); 658e1defba4STianfei Zhang if (!id) { 659e1defba4STianfei Zhang dev_err(max10 "max10 compatible not found\n"); 660e1defba4STianfei Zhang ret = -ENODEV; 661e41856b5SWei Huang } else { 662e1defba4STianfei Zhang max10->flags |= MAX10_FLAGS_DEVICE_TABLE; 663e1defba4STianfei Zhang max10->id = id; 664e1defba4STianfei Zhang max10->fdt_root = fdt_root; 665e41856b5SWei Huang } 666e41856b5SWei Huang } 667e1defba4STianfei Zhang 668e1defba4STianfei Zhang return ret; 669e1defba4STianfei Zhang } 670e1defba4STianfei Zhang 67145f30172STianfei Zhang static u64 fdt_get_number(const fdt32_t *cell, int size) 67245f30172STianfei Zhang { 67345f30172STianfei Zhang u64 r = 0; 67445f30172STianfei Zhang 67545f30172STianfei Zhang while (size--) 67645f30172STianfei Zhang r = (r << 32) | fdt32_to_cpu(*cell++); 67745f30172STianfei Zhang 67845f30172STianfei Zhang return r; 67945f30172STianfei Zhang } 68045f30172STianfei Zhang 68145f30172STianfei Zhang static int fdt_get_reg(const void *fdt, int node, unsigned int idx, 68245f30172STianfei Zhang u64 *start, u64 *size) 68345f30172STianfei Zhang { 68445f30172STianfei Zhang const fdt32_t *prop, *end; 68545f30172STianfei Zhang int na = 0, ns = 0, len = 0, parent; 68645f30172STianfei Zhang 68745f30172STianfei Zhang parent = fdt_parent_offset(fdt, node); 68845f30172STianfei Zhang if (parent < 0) 68945f30172STianfei Zhang return parent; 69045f30172STianfei Zhang 69145f30172STianfei Zhang prop = fdt_getprop(fdt, parent, "#address-cells", NULL); 69245f30172STianfei Zhang na = prop ? fdt32_to_cpu(*prop) : 2; 69345f30172STianfei Zhang 69445f30172STianfei Zhang prop = fdt_getprop(fdt, parent, "#size-cells", NULL); 69545f30172STianfei Zhang ns = prop ? fdt32_to_cpu(*prop) : 2; 69645f30172STianfei Zhang 69745f30172STianfei Zhang prop = fdt_getprop(fdt, node, "reg", &len); 69845f30172STianfei Zhang if (!prop) 69945f30172STianfei Zhang return -FDT_ERR_NOTFOUND; 70045f30172STianfei Zhang 70145f30172STianfei Zhang end = prop + len/sizeof(*prop); 70245f30172STianfei Zhang prop = prop + (na + ns) * idx; 70345f30172STianfei Zhang 70445f30172STianfei Zhang if (prop + na + ns > end) 70545f30172STianfei Zhang return -FDT_ERR_NOTFOUND; 70645f30172STianfei Zhang 70745f30172STianfei Zhang *start = fdt_get_number(prop, na); 70845f30172STianfei Zhang *size = fdt_get_number(prop + na, ns); 70945f30172STianfei Zhang 71045f30172STianfei Zhang return 0; 71145f30172STianfei Zhang } 71245f30172STianfei Zhang 71345f30172STianfei Zhang static int __fdt_stringlist_search(const void *fdt, int offset, 71445f30172STianfei Zhang const char *prop, const char *string) 71545f30172STianfei Zhang { 71645f30172STianfei Zhang int length, len, index = 0; 71745f30172STianfei Zhang const char *list, *end; 71845f30172STianfei Zhang 71945f30172STianfei Zhang list = fdt_getprop(fdt, offset, prop, &length); 72045f30172STianfei Zhang if (!list) 72145f30172STianfei Zhang return length; 72245f30172STianfei Zhang 72345f30172STianfei Zhang len = strlen(string) + 1; 72445f30172STianfei Zhang end = list + length; 72545f30172STianfei Zhang 72645f30172STianfei Zhang while (list < end) { 72745f30172STianfei Zhang length = strnlen(list, end - list) + 1; 72845f30172STianfei Zhang 72945f30172STianfei Zhang if (list + length > end) 73045f30172STianfei Zhang return -FDT_ERR_BADVALUE; 73145f30172STianfei Zhang 73245f30172STianfei Zhang if (length == len && memcmp(list, string, length) == 0) 73345f30172STianfei Zhang return index; 73445f30172STianfei Zhang 73545f30172STianfei Zhang list += length; 73645f30172STianfei Zhang index++; 73745f30172STianfei Zhang } 73845f30172STianfei Zhang 73945f30172STianfei Zhang return -FDT_ERR_NOTFOUND; 74045f30172STianfei Zhang } 74145f30172STianfei Zhang 74245f30172STianfei Zhang static int fdt_get_named_reg(const void *fdt, int node, const char *name, 74345f30172STianfei Zhang u64 *start, u64 *size) 74445f30172STianfei Zhang { 74545f30172STianfei Zhang int idx; 74645f30172STianfei Zhang 74745f30172STianfei Zhang idx = __fdt_stringlist_search(fdt, node, "reg-names", name); 74845f30172STianfei Zhang if (idx < 0) 74945f30172STianfei Zhang return idx; 75045f30172STianfei Zhang 75145f30172STianfei Zhang return fdt_get_reg(fdt, node, idx, start, size); 75245f30172STianfei Zhang } 75345f30172STianfei Zhang 7544a19f891STianfei Zhang static void max10_sensor_uinit(struct intel_max10_device *dev) 75545f30172STianfei Zhang { 75611986223SStephen Hemminger struct opae_sensor_info *info, *next; 75745f30172STianfei Zhang 75811986223SStephen Hemminger TAILQ_FOREACH_SAFE(info, &dev->opae_sensor_list, node, next) { 7594a19f891STianfei Zhang TAILQ_REMOVE(&dev->opae_sensor_list, info, node); 76045f30172STianfei Zhang opae_free(info); 76145f30172STianfei Zhang } 76245f30172STianfei Zhang } 76345f30172STianfei Zhang 76445f30172STianfei Zhang static bool sensor_reg_valid(struct sensor_reg *reg) 76545f30172STianfei Zhang { 76645f30172STianfei Zhang return !!reg->size; 76745f30172STianfei Zhang } 76845f30172STianfei Zhang 7694a19f891STianfei Zhang static int max10_add_sensor(struct intel_max10_device *dev, 7704a19f891STianfei Zhang struct raw_sensor_info *info, struct opae_sensor_info *sensor) 77145f30172STianfei Zhang { 77245f30172STianfei Zhang int i; 77345f30172STianfei Zhang int ret = 0; 77445f30172STianfei Zhang unsigned int val; 77545f30172STianfei Zhang 77645f30172STianfei Zhang if (!info || !sensor) 77745f30172STianfei Zhang return -ENODEV; 77845f30172STianfei Zhang 77945f30172STianfei Zhang sensor->id = info->id; 78045f30172STianfei Zhang sensor->name = info->name; 78145f30172STianfei Zhang sensor->type = info->type; 78245f30172STianfei Zhang sensor->multiplier = info->multiplier; 78345f30172STianfei Zhang 78445f30172STianfei Zhang for (i = SENSOR_REG_VALUE; i < SENSOR_REG_MAX; i++) { 78545f30172STianfei Zhang if (!sensor_reg_valid(&info->regs[i])) 78645f30172STianfei Zhang continue; 78745f30172STianfei Zhang 7884a19f891STianfei Zhang ret = max10_sys_read(dev, info->regs[i].regoff, &val); 78945f30172STianfei Zhang if (ret) 79045f30172STianfei Zhang break; 79145f30172STianfei Zhang 7924a19f891STianfei Zhang if (val == 0xdeadbeef) { 7934a19f891STianfei Zhang dev_debug(dev, "%s: sensor:%s invalid 0x%x at:%d\n", 7944a19f891STianfei Zhang __func__, sensor->name, val, i); 79545f30172STianfei Zhang continue; 7964a19f891STianfei Zhang } 79745f30172STianfei Zhang 79845f30172STianfei Zhang val *= info->multiplier; 79945f30172STianfei Zhang 80045f30172STianfei Zhang switch (i) { 80145f30172STianfei Zhang case SENSOR_REG_VALUE: 80245f30172STianfei Zhang sensor->value_reg = info->regs[i].regoff; 80345f30172STianfei Zhang sensor->flags |= OPAE_SENSOR_VALID; 80445f30172STianfei Zhang break; 80545f30172STianfei Zhang case SENSOR_REG_HIGH_WARN: 80645f30172STianfei Zhang sensor->high_warn = val; 80745f30172STianfei Zhang sensor->flags |= OPAE_SENSOR_HIGH_WARN_VALID; 80845f30172STianfei Zhang break; 80945f30172STianfei Zhang case SENSOR_REG_HIGH_FATAL: 81045f30172STianfei Zhang sensor->high_fatal = val; 81145f30172STianfei Zhang sensor->flags |= OPAE_SENSOR_HIGH_FATAL_VALID; 81245f30172STianfei Zhang break; 81345f30172STianfei Zhang case SENSOR_REG_LOW_WARN: 81445f30172STianfei Zhang sensor->low_warn = val; 81545f30172STianfei Zhang sensor->flags |= OPAE_SENSOR_LOW_WARN_VALID; 81645f30172STianfei Zhang break; 81745f30172STianfei Zhang case SENSOR_REG_LOW_FATAL: 81845f30172STianfei Zhang sensor->low_fatal = val; 81945f30172STianfei Zhang sensor->flags |= OPAE_SENSOR_LOW_FATAL_VALID; 82045f30172STianfei Zhang break; 82145f30172STianfei Zhang case SENSOR_REG_HYSTERESIS: 82245f30172STianfei Zhang sensor->hysteresis = val; 82345f30172STianfei Zhang sensor->flags |= OPAE_SENSOR_HYSTERESIS_VALID; 82445f30172STianfei Zhang break; 82545f30172STianfei Zhang } 82645f30172STianfei Zhang } 82745f30172STianfei Zhang 82845f30172STianfei Zhang return ret; 82945f30172STianfei Zhang } 83045f30172STianfei Zhang 83171da60b8STianfei Zhang static int 83271da60b8STianfei Zhang max10_sensor_init(struct intel_max10_device *dev, int parent) 83345f30172STianfei Zhang { 83445f30172STianfei Zhang int i, ret = 0, offset = 0; 83545f30172STianfei Zhang const fdt32_t *num; 83645f30172STianfei Zhang const char *ptr; 83745f30172STianfei Zhang u64 start, size; 83845f30172STianfei Zhang struct raw_sensor_info *raw; 83945f30172STianfei Zhang struct opae_sensor_info *sensor; 84045f30172STianfei Zhang char *fdt_root = dev->fdt_root; 84145f30172STianfei Zhang 84245f30172STianfei Zhang if (!fdt_root) { 84345f30172STianfei Zhang dev_debug(dev, "skip sensor init as not find Device Tree\n"); 84445f30172STianfei Zhang return 0; 84545f30172STianfei Zhang } 84645f30172STianfei Zhang 84771da60b8STianfei Zhang fdt_for_each_subnode(offset, fdt_root, parent) { 84845f30172STianfei Zhang ptr = fdt_get_name(fdt_root, offset, NULL); 84945f30172STianfei Zhang if (!ptr) { 85045f30172STianfei Zhang dev_err(dev, "failed to fdt get name\n"); 85145f30172STianfei Zhang continue; 85245f30172STianfei Zhang } 85345f30172STianfei Zhang 85445f30172STianfei Zhang if (!strstr(ptr, "sensor")) { 85545f30172STianfei Zhang dev_debug(dev, "%s is not a sensor node\n", ptr); 85645f30172STianfei Zhang continue; 85745f30172STianfei Zhang } 85845f30172STianfei Zhang 85945f30172STianfei Zhang dev_debug(dev, "found sensor node %s\n", ptr); 86045f30172STianfei Zhang 86145f30172STianfei Zhang raw = (struct raw_sensor_info *)opae_zmalloc(sizeof(*raw)); 86245f30172STianfei Zhang if (!raw) { 86345f30172STianfei Zhang ret = -ENOMEM; 86445f30172STianfei Zhang goto free_sensor; 86545f30172STianfei Zhang } 86645f30172STianfei Zhang 86745f30172STianfei Zhang raw->name = fdt_getprop(fdt_root, offset, "sensor_name", NULL); 86845f30172STianfei Zhang if (!raw->name) { 86945f30172STianfei Zhang ret = -EINVAL; 87045f30172STianfei Zhang goto free_sensor; 87145f30172STianfei Zhang } 87245f30172STianfei Zhang 87345f30172STianfei Zhang raw->type = fdt_getprop(fdt_root, offset, "type", NULL); 87445f30172STianfei Zhang if (!raw->type) { 87545f30172STianfei Zhang ret = -EINVAL; 87645f30172STianfei Zhang goto free_sensor; 87745f30172STianfei Zhang } 87845f30172STianfei Zhang 87945f30172STianfei Zhang for (i = SENSOR_REG_VALUE; i < SENSOR_REG_MAX; i++) { 88045f30172STianfei Zhang ret = fdt_get_named_reg(fdt_root, offset, 88145f30172STianfei Zhang sensor_reg_name[i], &start, 88245f30172STianfei Zhang &size); 88345f30172STianfei Zhang if (ret) { 88445f30172STianfei Zhang dev_debug(dev, "no found %d: sensor node %s, %s\n", 88545f30172STianfei Zhang ret, ptr, sensor_reg_name[i]); 88645f30172STianfei Zhang if (i == SENSOR_REG_VALUE) { 88745f30172STianfei Zhang ret = -EINVAL; 88845f30172STianfei Zhang goto free_sensor; 88945f30172STianfei Zhang } 89045f30172STianfei Zhang 89145f30172STianfei Zhang continue; 89245f30172STianfei Zhang } 89345f30172STianfei Zhang 89471da60b8STianfei Zhang /* This is a hack to compatible with non-secure 89571da60b8STianfei Zhang * solution. If sensors are included in root node, 89671da60b8STianfei Zhang * then it's non-secure dtb, which use absolute addr 89771da60b8STianfei Zhang * of non-secure solution. 89871da60b8STianfei Zhang */ 89971da60b8STianfei Zhang if (parent) 90045f30172STianfei Zhang raw->regs[i].regoff = start; 90171da60b8STianfei Zhang else 90271da60b8STianfei Zhang raw->regs[i].regoff = start - 90371da60b8STianfei Zhang MAX10_BASE_ADDR; 90445f30172STianfei Zhang raw->regs[i].size = size; 90545f30172STianfei Zhang } 90645f30172STianfei Zhang 90745f30172STianfei Zhang num = fdt_getprop(fdt_root, offset, "id", NULL); 90845f30172STianfei Zhang if (!num) { 90945f30172STianfei Zhang ret = -EINVAL; 91045f30172STianfei Zhang goto free_sensor; 91145f30172STianfei Zhang } 91245f30172STianfei Zhang 91345f30172STianfei Zhang raw->id = fdt32_to_cpu(*num); 91445f30172STianfei Zhang num = fdt_getprop(fdt_root, offset, "multiplier", NULL); 91545f30172STianfei Zhang raw->multiplier = num ? fdt32_to_cpu(*num) : 1; 91645f30172STianfei Zhang 9174a19f891STianfei Zhang dev_debug(dev, "found sensor from DTB: %s: %s: %u: %u\n", 91845f30172STianfei Zhang raw->name, raw->type, 91945f30172STianfei Zhang raw->id, raw->multiplier); 92045f30172STianfei Zhang 92145f30172STianfei Zhang for (i = SENSOR_REG_VALUE; i < SENSOR_REG_MAX; i++) 92245f30172STianfei Zhang dev_debug(dev, "sensor reg[%d]: %x: %zu\n", 92345f30172STianfei Zhang i, raw->regs[i].regoff, 92445f30172STianfei Zhang raw->regs[i].size); 92545f30172STianfei Zhang 92645f30172STianfei Zhang sensor = opae_zmalloc(sizeof(*sensor)); 92745f30172STianfei Zhang if (!sensor) { 92845f30172STianfei Zhang ret = -EINVAL; 92945f30172STianfei Zhang goto free_sensor; 93045f30172STianfei Zhang } 93145f30172STianfei Zhang 9324a19f891STianfei Zhang if (max10_add_sensor(dev, raw, sensor)) { 93345f30172STianfei Zhang ret = -EINVAL; 93445f30172STianfei Zhang opae_free(sensor); 93545f30172STianfei Zhang goto free_sensor; 93645f30172STianfei Zhang } 93745f30172STianfei Zhang 9384a19f891STianfei Zhang if (sensor->flags & OPAE_SENSOR_VALID) { 9394a19f891STianfei Zhang TAILQ_INSERT_TAIL(&dev->opae_sensor_list, sensor, node); 9404a19f891STianfei Zhang dev_info(dev, "found valid sensor: %s\n", sensor->name); 9414a19f891STianfei Zhang } else 94245f30172STianfei Zhang opae_free(sensor); 94345f30172STianfei Zhang 94445f30172STianfei Zhang opae_free(raw); 94545f30172STianfei Zhang } 94645f30172STianfei Zhang 94745f30172STianfei Zhang return 0; 94845f30172STianfei Zhang 94945f30172STianfei Zhang free_sensor: 95045f30172STianfei Zhang if (raw) 95145f30172STianfei Zhang opae_free(raw); 9524a19f891STianfei Zhang max10_sensor_uinit(dev); 95345f30172STianfei Zhang return ret; 95445f30172STianfei Zhang } 95545f30172STianfei Zhang 95671da60b8STianfei Zhang static int check_max10_version(struct intel_max10_device *dev) 95771da60b8STianfei Zhang { 95871da60b8STianfei Zhang unsigned int v; 95971da60b8STianfei Zhang 9604a19f891STianfei Zhang if (!max10_reg_read(dev, MAX10_SEC_BASE_ADDR + MAX10_BUILD_VER, 96171da60b8STianfei Zhang &v)) { 96271da60b8STianfei Zhang if (v != 0xffffffff) { 96371da60b8STianfei Zhang dev_info(dev, "secure MAX10 detected\n"); 96471da60b8STianfei Zhang dev->flags |= MAX10_FLAGS_SECURE; 96571da60b8STianfei Zhang } else { 96671da60b8STianfei Zhang dev_info(dev, "non-secure MAX10 detected\n"); 96771da60b8STianfei Zhang } 96871da60b8STianfei Zhang return 0; 96971da60b8STianfei Zhang } 97071da60b8STianfei Zhang 97171da60b8STianfei Zhang return -ENODEV; 97271da60b8STianfei Zhang } 97371da60b8STianfei Zhang 974a05bd1b4SWei Huang static int max10_staging_area_init(struct intel_max10_device *dev) 975a05bd1b4SWei Huang { 976a05bd1b4SWei Huang char *fdt_root = dev->fdt_root; 977a05bd1b4SWei Huang int ret, offset = 0; 978a05bd1b4SWei Huang u64 start, size; 979a05bd1b4SWei Huang 980a05bd1b4SWei Huang if (!fdt_root) { 981a05bd1b4SWei Huang dev_debug(dev, 982a05bd1b4SWei Huang "skip staging area init as not find Device Tree\n"); 983a05bd1b4SWei Huang return -ENODEV; 984a05bd1b4SWei Huang } 985a05bd1b4SWei Huang 986a05bd1b4SWei Huang dev->staging_area_size = 0; 987a05bd1b4SWei Huang 988a05bd1b4SWei Huang fdt_for_each_subnode(offset, fdt_root, 0) { 989a05bd1b4SWei Huang if (fdt_node_check_compatible(fdt_root, offset, 990a05bd1b4SWei Huang "ifpga-sec-mgr,staging-area")) 991a05bd1b4SWei Huang continue; 992a05bd1b4SWei Huang 993a05bd1b4SWei Huang ret = fdt_get_reg(fdt_root, offset, 0, &start, &size); 99492a3b62bSWei Huang if (ret) 99592a3b62bSWei Huang return ret; 99692a3b62bSWei Huang 99792a3b62bSWei Huang if ((start & 0x3) || (start > MAX_STAGING_AREA_BASE) || 99892a3b62bSWei Huang (size > MAX_STAGING_AREA_SIZE)) 99992a3b62bSWei Huang return -EINVAL; 100092a3b62bSWei Huang 1001a05bd1b4SWei Huang dev->staging_area_base = start; 1002a05bd1b4SWei Huang dev->staging_area_size = size; 100392a3b62bSWei Huang 1004a05bd1b4SWei Huang return ret; 1005a05bd1b4SWei Huang } 1006a05bd1b4SWei Huang 1007a05bd1b4SWei Huang return -ENODEV; 1008a05bd1b4SWei Huang } 1009a05bd1b4SWei Huang 101071da60b8STianfei Zhang static int 101171da60b8STianfei Zhang max10_secure_hw_init(struct intel_max10_device *dev) 101271da60b8STianfei Zhang { 101371da60b8STianfei Zhang int offset, sysmgr_offset = 0; 101471da60b8STianfei Zhang char *fdt_root; 101571da60b8STianfei Zhang 101671da60b8STianfei Zhang fdt_root = dev->fdt_root; 101771da60b8STianfei Zhang if (!fdt_root) { 101871da60b8STianfei Zhang dev_debug(dev, "skip init as not find Device Tree\n"); 101971da60b8STianfei Zhang return 0; 102071da60b8STianfei Zhang } 102171da60b8STianfei Zhang 102271da60b8STianfei Zhang fdt_for_each_subnode(offset, fdt_root, 0) { 102371da60b8STianfei Zhang if (!fdt_node_check_compatible(fdt_root, offset, 102471da60b8STianfei Zhang "intel-max10,system-manager")) { 102571da60b8STianfei Zhang sysmgr_offset = offset; 102671da60b8STianfei Zhang break; 102771da60b8STianfei Zhang } 102871da60b8STianfei Zhang } 102971da60b8STianfei Zhang 103071da60b8STianfei Zhang max10_check_capability(dev); 103171da60b8STianfei Zhang 103271da60b8STianfei Zhang max10_sensor_init(dev, sysmgr_offset); 103371da60b8STianfei Zhang 1034a05bd1b4SWei Huang max10_staging_area_init(dev); 1035a05bd1b4SWei Huang 103671da60b8STianfei Zhang return 0; 103771da60b8STianfei Zhang } 103871da60b8STianfei Zhang 103971da60b8STianfei Zhang static int 104071da60b8STianfei Zhang max10_non_secure_hw_init(struct intel_max10_device *dev) 104171da60b8STianfei Zhang { 104271da60b8STianfei Zhang max10_check_capability(dev); 104371da60b8STianfei Zhang 104471da60b8STianfei Zhang max10_sensor_init(dev, 0); 104571da60b8STianfei Zhang 104671da60b8STianfei Zhang return 0; 104771da60b8STianfei Zhang } 104871da60b8STianfei Zhang 10497c4fe2adSWei Huang int max10_get_fpga_load_info(struct intel_max10_device *dev, unsigned int *val) 10507c4fe2adSWei Huang { 10517c4fe2adSWei Huang int ret; 10527c4fe2adSWei Huang unsigned int value; 10537c4fe2adSWei Huang 10547c4fe2adSWei Huang /* read FPGA loading information */ 10557c4fe2adSWei Huang ret = max10_sys_read(dev, dev->csr->fpga_page_info, &value); 10567c4fe2adSWei Huang if (ret) { 10577c4fe2adSWei Huang dev_err(dev, "fail to get FPGA loading info\n"); 10587c4fe2adSWei Huang return ret; 10597c4fe2adSWei Huang } 10607c4fe2adSWei Huang 10617c4fe2adSWei Huang if (dev->type == M10_N3000) 10627c4fe2adSWei Huang *val = value & 0x7; 10637c4fe2adSWei Huang else if (dev->type == M10_N6000) { 10647c4fe2adSWei Huang if (!GET_FIELD(PMCI_FPGA_CONFIGURED, value)) 10657c4fe2adSWei Huang return -EINVAL; 10667c4fe2adSWei Huang *val = GET_FIELD(PMCI_FPGA_BOOT_PAGE, value); 10677c4fe2adSWei Huang } 10687c4fe2adSWei Huang 10697c4fe2adSWei Huang return 0; 10707c4fe2adSWei Huang } 10717c4fe2adSWei Huang 10727c4fe2adSWei Huang int max10_get_bmc_version(struct intel_max10_device *dev, unsigned int *val) 10737c4fe2adSWei Huang { 10747c4fe2adSWei Huang int ret; 10757c4fe2adSWei Huang 10767c4fe2adSWei Huang ret = max10_sys_read(dev, dev->csr->build_version, val); 10777c4fe2adSWei Huang if (ret) 10787c4fe2adSWei Huang return ret; 10797c4fe2adSWei Huang 10807c4fe2adSWei Huang return 0; 10817c4fe2adSWei Huang } 10827c4fe2adSWei Huang 10837c4fe2adSWei Huang int max10_get_bmcfw_version(struct intel_max10_device *dev, unsigned int *val) 10847c4fe2adSWei Huang { 10857c4fe2adSWei Huang int ret; 10867c4fe2adSWei Huang 10877c4fe2adSWei Huang ret = max10_sys_read(dev, dev->csr->fw_version, val); 10887c4fe2adSWei Huang if (ret) 10897c4fe2adSWei Huang return ret; 10907c4fe2adSWei Huang 10917c4fe2adSWei Huang return 0; 10927c4fe2adSWei Huang } 10937c4fe2adSWei Huang 1094ca6eb0f7SWei Huang static const struct m10bmc_csr m10bmc_spi_csr = { 1095ca6eb0f7SWei Huang .base = MAX10_SEC_BASE_ADDR, 1096ca6eb0f7SWei Huang .build_version = MAX10_BUILD_VER, 1097ca6eb0f7SWei Huang .fw_version = NIOS2_FW_VERSION, 1098ca6eb0f7SWei Huang .fpga_page_info = FPGA_PAGE_INFO, 1099ca6eb0f7SWei Huang .doorbell = MAX10_DOORBELL, 1100ca6eb0f7SWei Huang .auth_result = MAX10_AUTH_RESULT, 1101ca6eb0f7SWei Huang }; 1102473c88f9SBruce Richardson 1103ca6eb0f7SWei Huang static const struct m10bmc_csr m10bmc_pmci_csr = { 1104ca6eb0f7SWei Huang .base = M10BMC_PMCI_SYS_BASE, 1105ca6eb0f7SWei Huang .build_version = M10BMC_PMCI_BUILD_VER, 1106ca6eb0f7SWei Huang .fw_version = NIOS2_PMCI_FW_VERSION, 1107ca6eb0f7SWei Huang .fpga_page_info = M10BMC_PMCI_FPGA_CONF_STS, 1108ca6eb0f7SWei Huang .doorbell = M10BMC_PMCI_DOORBELL, 1109ca6eb0f7SWei Huang .auth_result = M10BMC_PMCI_AUTH_RESULT, 1110ca6eb0f7SWei Huang }; 1111ca6eb0f7SWei Huang 1112528a9fc2SWei Huang static const struct max10_sensor_raw_data n6000bmc_temp_tbl[] = { 1113528a9fc2SWei Huang { 0x444, 0x448, 0x44c, 0x0, 0x0, 500, 1114528a9fc2SWei Huang "FPGA E-TILE Temperature #1" }, 1115528a9fc2SWei Huang { 0x450, 0x454, 0x458, 0x0, 0x0, 500, 1116528a9fc2SWei Huang "FPGA E-TILE Temperature #2" }, 1117528a9fc2SWei Huang { 0x45c, 0x460, 0x464, 0x0, 0x0, 500, 1118528a9fc2SWei Huang "FPGA E-TILE Temperature #3" }, 1119528a9fc2SWei Huang { 0x468, 0x46c, 0x470, 0x0, 0x0, 500, 1120528a9fc2SWei Huang "FPGA E-TILE Temperature #4" }, 1121528a9fc2SWei Huang { 0x474, 0x478, 0x47c, 0x0, 0x0, 500, 1122528a9fc2SWei Huang "FPGA P-TILE Temperature" }, 1123528a9fc2SWei Huang { 0x484, 0x488, 0x48c, 0x0, 0x0, 500, 1124528a9fc2SWei Huang "FPGA FABRIC Digital Temperature#1" }, 1125528a9fc2SWei Huang { 0x490, 0x494, 0x498, 0x0, 0x0, 500, 1126528a9fc2SWei Huang "FPGA FABRIC Digital Temperature#2" }, 1127528a9fc2SWei Huang { 0x49c, 0x4a0, 0x4a4, 0x0, 0x0, 500, 1128528a9fc2SWei Huang "FPGA FABRIC Digital Temperature#3" }, 1129528a9fc2SWei Huang { 0x4a8, 0x4ac, 0x4b0, 0x0, 0x0, 500, 1130528a9fc2SWei Huang "FPGA FABRIC Digital Temperature#4" }, 1131528a9fc2SWei Huang { 0x4b4, 0x4b8, 0x4bc, 0x0, 0x0, 500, 1132528a9fc2SWei Huang "FPGA FABRIC Digital Temperature#5" }, 1133528a9fc2SWei Huang { 0x4c0, 0x4c4, 0x4c8, 0x0, 0x0, 500, 1134528a9fc2SWei Huang "FPGA FABRIC Remote Digital Temperature#1" }, 1135528a9fc2SWei Huang { 0x4cc, 0x4d0, 0x4d4, 0x0, 0x0, 500, 1136528a9fc2SWei Huang "FPGA FABRIC Remote Digital Temperature#2" }, 1137528a9fc2SWei Huang { 0x4d8, 0x4dc, 0x4e0, 0x0, 0x0, 500, 1138528a9fc2SWei Huang "FPGA FABRIC Remote Digital Temperature#3" }, 1139528a9fc2SWei Huang { 0x4e4, 0x4e8, 0x4ec, 0x0, 0x0, 500, 1140528a9fc2SWei Huang "FPGA FABRIC Remote Digital Temperature#4" }, 1141528a9fc2SWei Huang { 0x4f0, 0x4f4, 0x4f8, 0x0, 0x0, 500, 1142528a9fc2SWei Huang "Board Top Near FPGA Temperature" }, 1143528a9fc2SWei Huang { 0x4fc, 0x500, 0x504, 0x52c, 0x0, 500, 1144528a9fc2SWei Huang "Board Bottom Near CVL Temperature" }, 1145528a9fc2SWei Huang { 0x508, 0x50c, 0x510, 0x52c, 0x0, 500, 1146528a9fc2SWei Huang "Board Top East Near VRs Temperature" }, 1147528a9fc2SWei Huang { 0x514, 0x518, 0x51c, 0x52c, 0x0, 500, 1148528a9fc2SWei Huang "Columbiaville Die Temperature" }, 1149528a9fc2SWei Huang { 0x520, 0x524, 0x528, 0x52c, 0x0, 500, 1150528a9fc2SWei Huang "Board Rear Side Temperature" }, 1151528a9fc2SWei Huang { 0x530, 0x534, 0x538, 0x52c, 0x0, 500, 1152528a9fc2SWei Huang "Board Front Side Temperature" }, 1153528a9fc2SWei Huang { 0x53c, 0x540, 0x544, 0x0, 0x0, 500, 1154528a9fc2SWei Huang "QSFP1 Temperature" }, 1155528a9fc2SWei Huang { 0x548, 0x54c, 0x550, 0x0, 0x0, 500, 1156528a9fc2SWei Huang "QSFP2 Temperature" }, 1157528a9fc2SWei Huang { 0x554, 0x0, 0x0, 0x0, 0x0, 500, 1158528a9fc2SWei Huang "FPGA Core Voltage Phase 0 VR Temperature" }, 1159528a9fc2SWei Huang { 0x560, 0x0, 0x0, 0x0, 0x0, 500, 1160528a9fc2SWei Huang "FPGA Core Voltage Phase 1 VR Temperature" }, 1161528a9fc2SWei Huang { 0x56c, 0x0, 0x0, 0x0, 0x0, 500, 1162528a9fc2SWei Huang "FPGA Core Voltage Phase 2 VR Temperature" }, 1163528a9fc2SWei Huang { 0x578, 0x0, 0x0, 0x0, 0x0, 500, 1164528a9fc2SWei Huang "FPGA Core Voltage VR Controller Temperature" }, 1165528a9fc2SWei Huang { 0x584, 0x0, 0x0, 0x0, 0x0, 500, 1166528a9fc2SWei Huang "FPGA VCCH VR Temperature" }, 1167528a9fc2SWei Huang { 0x590, 0x0, 0x0, 0x0, 0x0, 500, 1168528a9fc2SWei Huang "FPGA VCC_1V2 VR Temperature" }, 1169528a9fc2SWei Huang { 0x59c, 0x0, 0x0, 0x0, 0x0, 500, 1170528a9fc2SWei Huang "FPGA VCCH, VCC_1V2 VR Controller Temperature" }, 1171528a9fc2SWei Huang { 0x5a8, 0x0, 0x0, 0x0, 0x0, 500, 1172528a9fc2SWei Huang "3V3 VR Temperature" }, 1173528a9fc2SWei Huang { 0x5b4, 0x5b8, 0x5bc, 0x0, 0x0, 500, 1174528a9fc2SWei Huang "CVL Core Voltage VR Temperature" }, 1175528a9fc2SWei Huang { 0x5c4, 0x5c8, 0x5cc, 0x5c0, 0x0, 500, 1176528a9fc2SWei Huang "FPGA P-Tile Temperature [Remote]" }, 1177528a9fc2SWei Huang { 0x5d0, 0x5d4, 0x5d8, 0x5c0, 0x0, 500, 1178528a9fc2SWei Huang "FPGA E-Tile Temperature [Remote]" }, 1179528a9fc2SWei Huang { 0x5dc, 0x5e0, 0x5e4, 0x5c0, 0x0, 500, 1180528a9fc2SWei Huang "FPGA SDM Temperature [Remote]" }, 1181528a9fc2SWei Huang { 0x5e8, 0x5ec, 0x5f0, 0x5c0, 0x0, 500, 1182528a9fc2SWei Huang "FPGA Corner Temperature [Remote]" }, 1183528a9fc2SWei Huang }; 1184528a9fc2SWei Huang 1185528a9fc2SWei Huang static const struct max10_sensor_data n6000bmc_tmp_data = { 1186528a9fc2SWei Huang .type = SENSOR_TMP_NAME, 1187528a9fc2SWei Huang .number = ARRAY_SIZE(n6000bmc_temp_tbl), 1188528a9fc2SWei Huang .table = n6000bmc_temp_tbl, 1189528a9fc2SWei Huang }; 1190528a9fc2SWei Huang 1191528a9fc2SWei Huang static const struct max10_sensor_raw_data n6000bmc_in_tbl[] = { 1192528a9fc2SWei Huang { 0x5f4, 0x0, 0x0, 0x0, 0x0, 1, 1193528a9fc2SWei Huang "Inlet 12V PCIe Rail Voltage" }, 1194528a9fc2SWei Huang { 0x60c, 0x0, 0x0, 0x0, 0x0, 1, 1195528a9fc2SWei Huang "Inlet 12V Aux Rail Voltage" }, 1196528a9fc2SWei Huang { 0x624, 0x0, 0x0, 0x0, 0x0, 1, 1197528a9fc2SWei Huang "Inlet 3V3 PCIe Rail Voltage" }, 1198528a9fc2SWei Huang { 0x63c, 0x0, 0x0, 0x0, 0x0, 1, 1199528a9fc2SWei Huang "FPGA Core Voltage Rail Voltage" }, 1200528a9fc2SWei Huang { 0x644, 0x0, 0x0, 0x0, 0x0, 1, 1201528a9fc2SWei Huang "FPGA VCCH Rail Voltage" }, 1202528a9fc2SWei Huang { 0x64c, 0x0, 0x0, 0x0, 0x0, 1, 1203528a9fc2SWei Huang "FPGA VCC_1V2 Rail Voltage" }, 1204528a9fc2SWei Huang { 0x654, 0x0, 0x0, 0x0, 0x0, 1, 1205528a9fc2SWei Huang "FPGA VCCH_GXER_1V1, VCCA_1V8 Voltage" }, 1206528a9fc2SWei Huang { 0x664, 0x0, 0x0, 0x0, 0x0, 1, 1207528a9fc2SWei Huang "FPGA VCCIO_1V2 Voltage" }, 1208528a9fc2SWei Huang { 0x674, 0x0, 0x0, 0x0, 0x0, 1, 1209528a9fc2SWei Huang "CVL Non Core Rails Inlet Voltage" }, 1210528a9fc2SWei Huang { 0x684, 0x0, 0x0, 0x0, 0x0, 1, 1211528a9fc2SWei Huang "MAX10 & Board CLK PWR 3V3 Inlet Voltage" }, 1212528a9fc2SWei Huang { 0x694, 0x0, 0x0, 0x0, 0x0, 1, 1213528a9fc2SWei Huang "CVL Core Voltage Rail Voltage" }, 1214528a9fc2SWei Huang { 0x6ac, 0x0, 0x0, 0x0, 0x0, 1, 1215528a9fc2SWei Huang "Board 3V3 VR Voltage" }, 1216528a9fc2SWei Huang { 0x6b4, 0x0, 0x0, 0x0, 0x0, 1, 1217528a9fc2SWei Huang "QSFP 3V3 Rail Voltage" }, 1218528a9fc2SWei Huang { 0x6c4, 0x0, 0x0, 0x0, 0x0, 1, 1219528a9fc2SWei Huang "QSFP (Primary) Supply Rail Voltage" }, 1220528a9fc2SWei Huang { 0x6c8, 0x0, 0x0, 0x0, 0x0, 1, 1221528a9fc2SWei Huang "QSFP (Secondary) Supply Rail Voltage" }, 1222528a9fc2SWei Huang { 0x6cc, 0x0, 0x0, 0x0, 0x0, 1, 1223528a9fc2SWei Huang "VCCCLK_GXER_2V5 Voltage" }, 1224528a9fc2SWei Huang { 0x6d0, 0x0, 0x0, 0x0, 0x0, 1, 1225528a9fc2SWei Huang "AVDDH_1V1_CVL Voltage" }, 1226528a9fc2SWei Huang { 0x6d4, 0x0, 0x0, 0x0, 0x0, 1, 1227528a9fc2SWei Huang "VDDH_1V8_CVL Voltage" }, 1228528a9fc2SWei Huang { 0x6d8, 0x0, 0x0, 0x0, 0x0, 1, 1229528a9fc2SWei Huang "VCCA_PLL Voltage" }, 1230528a9fc2SWei Huang { 0x6e0, 0x0, 0x0, 0x0, 0x0, 1, 1231528a9fc2SWei Huang "VCCRT_GXER_0V9 Voltage" }, 1232528a9fc2SWei Huang { 0x6e8, 0x0, 0x0, 0x0, 0x0, 1, 1233528a9fc2SWei Huang "VCCRT_GXEL_0V9 Voltage" }, 1234528a9fc2SWei Huang { 0x6f0, 0x0, 0x0, 0x0, 0x0, 1, 1235528a9fc2SWei Huang "VCCH_GXPL_1V8 Voltage" }, 1236528a9fc2SWei Huang { 0x6f4, 0x0, 0x0, 0x0, 0x0, 1, 1237528a9fc2SWei Huang "VCCPT_1V8 Voltage" }, 1238528a9fc2SWei Huang { 0x6fc, 0x0, 0x0, 0x0, 0x0, 1, 1239528a9fc2SWei Huang "VCC_3V3_M10 Voltage" }, 1240528a9fc2SWei Huang { 0x700, 0x0, 0x0, 0x0, 0x0, 1, 1241528a9fc2SWei Huang "VCC_1V8_M10 Voltage" }, 1242528a9fc2SWei Huang { 0x704, 0x0, 0x0, 0x0, 0x0, 1, 1243528a9fc2SWei Huang "VCC_1V2_EMIF1_2_3 Voltage" }, 1244528a9fc2SWei Huang { 0x70c, 0x0, 0x0, 0x0, 0x0, 1, 1245528a9fc2SWei Huang "VCC_1V2_EMIF4_5 Voltage" }, 1246528a9fc2SWei Huang { 0x714, 0x0, 0x0, 0x0, 0x0, 1, 1247528a9fc2SWei Huang "VCCA_1V8 Voltage" }, 1248528a9fc2SWei Huang { 0x718, 0x0, 0x0, 0x0, 0x0, 1, 1249528a9fc2SWei Huang "VCCH_GXER_1V1 Voltage" }, 1250528a9fc2SWei Huang { 0x71c, 0x0, 0x0, 0x0, 0x0, 1, 1251528a9fc2SWei Huang "AVDD_ETH_0V9_CVL Voltage" }, 1252528a9fc2SWei Huang { 0x720, 0x0, 0x0, 0x0, 0x0, 1, 1253528a9fc2SWei Huang "AVDD_PCIE_0V9_CVL Voltage" }, 1254528a9fc2SWei Huang }; 1255528a9fc2SWei Huang 1256528a9fc2SWei Huang static const struct max10_sensor_data n6000bmc_in_data = { 1257528a9fc2SWei Huang .type = SENSOR_IN_NAME, 1258528a9fc2SWei Huang .number = ARRAY_SIZE(n6000bmc_in_tbl), 1259528a9fc2SWei Huang .table = n6000bmc_in_tbl, 1260528a9fc2SWei Huang }; 1261528a9fc2SWei Huang 1262528a9fc2SWei Huang static const struct max10_sensor_raw_data n6000bmc_curr_tbl[] = { 1263528a9fc2SWei Huang { 0x600, 0x604, 0x608, 0x0, 0x0, 1, 1264528a9fc2SWei Huang "Inlet 12V PCIe Rail Current" }, 1265528a9fc2SWei Huang { 0x618, 0x61c, 0x620, 0x0, 0x0, 1, 1266528a9fc2SWei Huang "Inlet 12V Aux Rail Current" }, 1267528a9fc2SWei Huang { 0x630, 0x634, 0x638, 0x0, 0x0, 1, 1268528a9fc2SWei Huang "Inlet 3V3 PCIe Rail Current" }, 1269528a9fc2SWei Huang { 0x640, 0x0, 0x0, 0x0, 0x0, 1, 1270528a9fc2SWei Huang "FPGA Core Voltage Rail Current" }, 1271528a9fc2SWei Huang { 0x648, 0x0, 0x0, 0x0, 0x0, 1, 1272528a9fc2SWei Huang "FPGA VCCH Rail Current" }, 1273528a9fc2SWei Huang { 0x650, 0x0, 0x0, 0x0, 0x0, 1, 1274528a9fc2SWei Huang "FPGA VCC_1V2 Rail Current" }, 1275528a9fc2SWei Huang { 0x658, 0x65c, 0x660, 0x0, 0x0, 1, 1276528a9fc2SWei Huang "FPGA VCCH_GXER_1V1, VCCA_1V8 Current" }, 1277528a9fc2SWei Huang { 0x668, 0x66c, 0x670, 0x0, 0x0, 1, 1278528a9fc2SWei Huang "FPGA VCCIO_1V2 Current" }, 1279528a9fc2SWei Huang { 0x678, 0x67c, 0x680, 0x0, 0x0, 1, 1280528a9fc2SWei Huang "CVL Non Core Rails Inlet Current" }, 1281528a9fc2SWei Huang { 0x688, 0x68c, 0x680, 0x0, 0x0, 1, 1282528a9fc2SWei Huang "MAX10 & Board CLK PWR 3V3 Inlet Current" }, 1283528a9fc2SWei Huang { 0x690, 0x0, 0x0, 0x0, 0x0, 1, 1284528a9fc2SWei Huang "CVL Core Voltage Rail Current" }, 1285528a9fc2SWei Huang { 0x6b0, 0x0, 0x0, 0x0, 0x0, 1, 1286528a9fc2SWei Huang "Board 3V3 VR Current" }, 1287528a9fc2SWei Huang { 0x6b8, 0x6bc, 0x670, 0x0, 0x0, 1, 1288528a9fc2SWei Huang "QSFP 3V3 Rail Current" }, 1289528a9fc2SWei Huang }; 1290528a9fc2SWei Huang 1291528a9fc2SWei Huang static const struct max10_sensor_data n6000bmc_curr_data = { 1292528a9fc2SWei Huang .type = SENSOR_CURR_NAME, 1293528a9fc2SWei Huang .number = ARRAY_SIZE(n6000bmc_curr_tbl), 1294528a9fc2SWei Huang .table = n6000bmc_curr_tbl, 1295528a9fc2SWei Huang }; 1296528a9fc2SWei Huang 1297528a9fc2SWei Huang static const struct max10_sensor_raw_data n6000bmc_power_tbl[] = { 1298528a9fc2SWei Huang { 0x724, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" }, 1299528a9fc2SWei Huang }; 1300528a9fc2SWei Huang 1301528a9fc2SWei Huang static const struct max10_sensor_data n6000bmc_power_data = { 1302528a9fc2SWei Huang .type = SENSOR_POWER_NAME, 1303528a9fc2SWei Huang .number = ARRAY_SIZE(n6000bmc_power_tbl), 1304528a9fc2SWei Huang .table = n6000bmc_power_tbl, 1305528a9fc2SWei Huang }; 1306528a9fc2SWei Huang 1307528a9fc2SWei Huang static const struct max10_sensor_board_data n6000bmc_sensor_board_data = { 1308528a9fc2SWei Huang .tables = { 1309528a9fc2SWei Huang [sensor_temp] = &n6000bmc_tmp_data, 1310528a9fc2SWei Huang [sensor_in] = &n6000bmc_in_data, 1311528a9fc2SWei Huang [sensor_curr] = &n6000bmc_curr_data, 1312528a9fc2SWei Huang [sensor_power] = &n6000bmc_power_data, 1313528a9fc2SWei Huang }, 1314528a9fc2SWei Huang }; 1315528a9fc2SWei Huang 1316528a9fc2SWei Huang static int get_sensor_data(struct intel_max10_device *dev, 1317528a9fc2SWei Huang struct opae_sensor_info *sensor, 1318528a9fc2SWei Huang unsigned int *value, 1319528a9fc2SWei Huang unsigned int reg, 1320528a9fc2SWei Huang unsigned int flags) 1321528a9fc2SWei Huang { 1322528a9fc2SWei Huang int ret; 1323528a9fc2SWei Huang unsigned int data; 1324528a9fc2SWei Huang 1325528a9fc2SWei Huang if (!reg) 1326528a9fc2SWei Huang return 0; 1327528a9fc2SWei Huang 1328528a9fc2SWei Huang ret = max10_sys_read(dev, reg, &data); 1329528a9fc2SWei Huang if (ret) 1330528a9fc2SWei Huang return ret; 1331528a9fc2SWei Huang 1332528a9fc2SWei Huang if (data == SENSOR_INVALID) { 1333528a9fc2SWei Huang dev_debug(dev, "%s: sensor:%s invalid 0x%x at:%d\n", 1334528a9fc2SWei Huang __func__, sensor->name, data, reg); 1335528a9fc2SWei Huang return ret; 1336528a9fc2SWei Huang } 1337528a9fc2SWei Huang 1338528a9fc2SWei Huang *value = data * sensor->multiplier; 1339528a9fc2SWei Huang sensor->flags |= flags; 1340528a9fc2SWei Huang 1341528a9fc2SWei Huang return 0; 1342528a9fc2SWei Huang } 1343528a9fc2SWei Huang 1344528a9fc2SWei Huang static int max10_parse_sensor_data(struct intel_max10_device *dev, 1345528a9fc2SWei Huang const struct max10_sensor_data *sdata) 1346528a9fc2SWei Huang { 1347528a9fc2SWei Huang struct opae_sensor_info *sensor; 1348528a9fc2SWei Huang const struct max10_sensor_raw_data *raw; 1349528a9fc2SWei Huang const struct max10_sensor_raw_data *table = 1350528a9fc2SWei Huang (const struct max10_sensor_raw_data *)sdata->table; 1351528a9fc2SWei Huang unsigned int i; 1352528a9fc2SWei Huang static unsigned int sensor_id; 1353528a9fc2SWei Huang int ret = 0; 1354528a9fc2SWei Huang 1355528a9fc2SWei Huang for (i = 0; i < sdata->number; i++) { 1356528a9fc2SWei Huang raw = &table[i]; 1357528a9fc2SWei Huang 1358528a9fc2SWei Huang sensor = opae_zmalloc(sizeof(*sensor)); 1359528a9fc2SWei Huang if (!sensor) { 1360528a9fc2SWei Huang ret = -EINVAL; 1361528a9fc2SWei Huang goto free_sensor; 1362528a9fc2SWei Huang } 1363528a9fc2SWei Huang 1364528a9fc2SWei Huang sensor->type = sdata->type; 1365528a9fc2SWei Huang sensor->id = sensor_id++; 1366528a9fc2SWei Huang 1367528a9fc2SWei Huang if (!raw->reg_input) 1368528a9fc2SWei Huang continue; 1369528a9fc2SWei Huang 1370528a9fc2SWei Huang sensor->value_reg = raw->reg_input; 1371528a9fc2SWei Huang sensor->multiplier = raw->multiplier; 1372528a9fc2SWei Huang sensor->name = raw->label; 1373528a9fc2SWei Huang 1374528a9fc2SWei Huang ret = get_sensor_data(dev, sensor, 1375528a9fc2SWei Huang &sensor->high_warn, 1376528a9fc2SWei Huang raw->reg_high_warn, 1377528a9fc2SWei Huang OPAE_SENSOR_HIGH_WARN_VALID); 1378528a9fc2SWei Huang if (ret) 1379528a9fc2SWei Huang break; 1380528a9fc2SWei Huang 1381528a9fc2SWei Huang ret = get_sensor_data(dev, sensor, 1382528a9fc2SWei Huang &sensor->high_fatal, 1383528a9fc2SWei Huang raw->reg_high_fatal, 1384528a9fc2SWei Huang OPAE_SENSOR_HIGH_FATAL_VALID); 1385528a9fc2SWei Huang if (ret) 1386528a9fc2SWei Huang break; 1387528a9fc2SWei Huang 1388528a9fc2SWei Huang ret = get_sensor_data(dev, sensor, 1389528a9fc2SWei Huang &sensor->hysteresis, 1390528a9fc2SWei Huang raw->reg_hyst, 1391528a9fc2SWei Huang OPAE_SENSOR_HYSTERESIS_VALID); 1392528a9fc2SWei Huang if (ret) 1393528a9fc2SWei Huang break; 1394528a9fc2SWei Huang 1395528a9fc2SWei Huang ret = get_sensor_data(dev, sensor, 1396528a9fc2SWei Huang &sensor->low_warn, 1397528a9fc2SWei Huang raw->reg_low_warn, 1398528a9fc2SWei Huang OPAE_SENSOR_LOW_WARN_VALID); 1399528a9fc2SWei Huang if (ret) 1400528a9fc2SWei Huang break; 1401528a9fc2SWei Huang 1402528a9fc2SWei Huang sensor->flags |= OPAE_SENSOR_VALID; 1403528a9fc2SWei Huang 1404528a9fc2SWei Huang TAILQ_INSERT_TAIL(&dev->opae_sensor_list, sensor, node); 1405528a9fc2SWei Huang dev_info(dev, "found valid sensor: %s\n", sensor->name); 1406528a9fc2SWei Huang } 1407528a9fc2SWei Huang 1408528a9fc2SWei Huang return ret; 1409528a9fc2SWei Huang 1410528a9fc2SWei Huang free_sensor: 1411528a9fc2SWei Huang max10_sensor_uinit(dev); 1412528a9fc2SWei Huang return ret; 1413528a9fc2SWei Huang } 1414528a9fc2SWei Huang 1415528a9fc2SWei Huang static int max10_sensor_init_table(struct intel_max10_device *dev, 1416528a9fc2SWei Huang const struct max10_sensor_board_data *data) 1417528a9fc2SWei Huang { 1418528a9fc2SWei Huang int ret = 0; 1419528a9fc2SWei Huang unsigned int i; 1420528a9fc2SWei Huang const struct max10_sensor_data *sdata; 1421528a9fc2SWei Huang 1422528a9fc2SWei Huang for (i = 0; i < ARRAY_SIZE(data->tables); i++) { 1423528a9fc2SWei Huang sdata = data->tables[i]; 1424528a9fc2SWei Huang if (!sdata) 1425528a9fc2SWei Huang continue; 1426528a9fc2SWei Huang ret = max10_parse_sensor_data(dev, sdata); 1427528a9fc2SWei Huang if (ret) 1428528a9fc2SWei Huang break; 1429528a9fc2SWei Huang } 1430528a9fc2SWei Huang 1431528a9fc2SWei Huang return ret; 1432528a9fc2SWei Huang } 1433528a9fc2SWei Huang 1434ca6eb0f7SWei Huang int 1435ca6eb0f7SWei Huang intel_max10_device_init(struct intel_max10_device *dev) 1436ca6eb0f7SWei Huang { 1437ca6eb0f7SWei Huang int ret = 0; 1438473c88f9SBruce Richardson 14394a19f891STianfei Zhang TAILQ_INIT(&dev->opae_sensor_list); 14404a19f891STianfei Zhang 1441473c88f9SBruce Richardson 1442ca6eb0f7SWei Huang if (dev->type == M10_N3000) { 1443ca6eb0f7SWei Huang dev->ops = &m10bmc_n3000_regmap; 1444ca6eb0f7SWei Huang dev->csr = &m10bmc_spi_csr; 1445473c88f9SBruce Richardson 1446b74ee6c8SWei Huang dev->raw_blk_ops.write_blk = n3000_bulk_raw_write; 1447b74ee6c8SWei Huang dev->raw_blk_ops.read_blk = n3000_bulk_raw_read; 1448b74ee6c8SWei Huang dev->bmc_ops.flash_read = n3000_flash_read; 1449b74ee6c8SWei Huang dev->bmc_ops.flash_write = n3000_flash_write; 1450b74ee6c8SWei Huang 145171da60b8STianfei Zhang /* check the max10 version */ 145271da60b8STianfei Zhang ret = check_max10_version(dev); 1453e1defba4STianfei Zhang if (ret) { 145471da60b8STianfei Zhang dev_err(dev, "Failed to find max10 hardware!\n"); 1455ca6eb0f7SWei Huang return ret; 1456e1defba4STianfei Zhang } 1457e1defba4STianfei Zhang 145871da60b8STianfei Zhang /* load the MAX10 device table */ 145971da60b8STianfei Zhang ret = init_max10_device_table(dev); 146071da60b8STianfei Zhang if (ret) { 146171da60b8STianfei Zhang dev_err(dev, "Init max10 device table fail\n"); 1462ca6eb0f7SWei Huang return ret; 146371da60b8STianfei Zhang } 146471da60b8STianfei Zhang 146571da60b8STianfei Zhang /* init max10 devices, like sensor*/ 146671da60b8STianfei Zhang if (dev->flags & MAX10_FLAGS_SECURE) 146771da60b8STianfei Zhang ret = max10_secure_hw_init(dev); 146871da60b8STianfei Zhang else 146971da60b8STianfei Zhang ret = max10_non_secure_hw_init(dev); 147071da60b8STianfei Zhang if (ret) { 147171da60b8STianfei Zhang dev_err(dev, "Failed to init max10 hardware!\n"); 1472e1defba4STianfei Zhang opae_free(dev->fdt_root); 1473ca6eb0f7SWei Huang return ret; 1474ca6eb0f7SWei Huang } 1475ca6eb0f7SWei Huang } else if (dev->type == M10_N6000) { 1476ca6eb0f7SWei Huang dev->ops = &m10bmc_pmci_regmap; 1477ca6eb0f7SWei Huang dev->csr = &m10bmc_pmci_csr; 1478ca6eb0f7SWei Huang dev->staging_area_size = MAX_STAGING_AREA_SIZE; 1479ca6eb0f7SWei Huang dev->flags |= MAX10_FLAGS_SECURE; 1480473c88f9SBruce Richardson 1481b74ee6c8SWei Huang dev->bmc_ops.flash_read = pmci_flash_bulk_read; 1482b74ee6c8SWei Huang dev->bmc_ops.flash_write = pmci_flash_bulk_write; 1483b74ee6c8SWei Huang dev->bmc_ops.check_flash_range = pmci_check_flash_address; 1484b74ee6c8SWei Huang 1485528a9fc2SWei Huang ret = max10_sensor_init_table(dev, &n6000bmc_sensor_board_data); 1486528a9fc2SWei Huang if (ret) 1487528a9fc2SWei Huang return ret; 1488528a9fc2SWei Huang 1489*d28809c2SAriel Otilibili pthread_mutex_init(&dev->bmc_ops.lock, NULL); 1490ca6eb0f7SWei Huang if (!dev->bmc_ops.mutex) 1491ca6eb0f7SWei Huang dev->bmc_ops.mutex = &dev->bmc_ops.lock; 1492ca6eb0f7SWei Huang } 1493ca6eb0f7SWei Huang 1494ca6eb0f7SWei Huang return ret; 1495473c88f9SBruce Richardson } 1496473c88f9SBruce Richardson 1497473c88f9SBruce Richardson int intel_max10_device_remove(struct intel_max10_device *dev) 1498473c88f9SBruce Richardson { 1499473c88f9SBruce Richardson if (!dev) 1500473c88f9SBruce Richardson return 0; 1501473c88f9SBruce Richardson 1502ca6eb0f7SWei Huang pthread_mutex_destroy(&dev->bmc_ops.lock); 150345f30172STianfei Zhang 1504ca6eb0f7SWei Huang if (dev->type == M10_N3000) { 1505ca6eb0f7SWei Huang max10_sensor_uinit(dev); 1506473c88f9SBruce Richardson 1507e1defba4STianfei Zhang if (dev->fdt_root) 1508e1defba4STianfei Zhang opae_free(dev->fdt_root); 1509ca6eb0f7SWei Huang } 1510473c88f9SBruce Richardson 1511473c88f9SBruce Richardson return 0; 1512473c88f9SBruce Richardson } 1513