1 /* 2 * DDR PHY Front End (DPFE) driver for Broadcom set top box SoCs 3 * 4 * Copyright (c) 2017 Broadcom 5 * 6 * Released under the GPLv2 only. 7 * SPDX-License-Identifier: GPL-2.0 8 */ 9 10 /* 11 * This driver provides access to the DPFE interface of Broadcom STB SoCs. 12 * The firmware running on the DCPU inside the DDR PHY can provide current 13 * information about the system's RAM, for instance the DRAM refresh rate. 14 * This can be used as an indirect indicator for the DRAM's temperature. 15 * Slower refresh rate means cooler RAM, higher refresh rate means hotter 16 * RAM. 17 * 18 * Throughout the driver, we use readl_relaxed() and writel_relaxed(), which 19 * already contain the appropriate le32_to_cpu()/cpu_to_le32() calls. 20 * 21 * Note regarding the loading of the firmware image: we use be32_to_cpu() 22 * and le_32_to_cpu(), so we can support the following four cases: 23 * - LE kernel + LE firmware image (the most common case) 24 * - LE kernel + BE firmware image 25 * - BE kernel + LE firmware image 26 * - BE kernel + BE firmware image 27 * 28 * The DPCU always runs in big endian mode. The firwmare image, however, can 29 * be in either format. Also, communication between host CPU and DCPU is 30 * always in little endian. 31 */ 32 33 #include <linux/delay.h> 34 #include <linux/firmware.h> 35 #include <linux/io.h> 36 #include <linux/module.h> 37 #include <linux/of_address.h> 38 #include <linux/platform_device.h> 39 40 #define DRVNAME "brcmstb-dpfe" 41 #define FIRMWARE_NAME "dpfe.bin" 42 43 /* DCPU register offsets */ 44 #define REG_DCPU_RESET 0x0 45 #define REG_TO_DCPU_MBOX 0x10 46 #define REG_TO_HOST_MBOX 0x14 47 48 /* Macros to process offsets returned by the DCPU */ 49 #define DRAM_MSG_ADDR_OFFSET 0x0 50 #define DRAM_MSG_TYPE_OFFSET 0x1c 51 #define DRAM_MSG_ADDR_MASK ((1UL << DRAM_MSG_TYPE_OFFSET) - 1) 52 #define DRAM_MSG_TYPE_MASK ((1UL << \ 53 (BITS_PER_LONG - DRAM_MSG_TYPE_OFFSET)) - 1) 54 55 /* Message RAM */ 56 #define DCPU_MSG_RAM_START 0x100 57 #define DCPU_MSG_RAM(x) (DCPU_MSG_RAM_START + (x) * sizeof(u32)) 58 59 /* DRAM Info Offsets & Masks */ 60 #define DRAM_INFO_INTERVAL 0x0 61 #define DRAM_INFO_MR4 0x4 62 #define DRAM_INFO_ERROR 0x8 63 #define DRAM_INFO_MR4_MASK 0xff 64 65 /* DRAM MR4 Offsets & Masks */ 66 #define DRAM_MR4_REFRESH 0x0 /* Refresh rate */ 67 #define DRAM_MR4_SR_ABORT 0x3 /* Self Refresh Abort */ 68 #define DRAM_MR4_PPRE 0x4 /* Post-package repair entry/exit */ 69 #define DRAM_MR4_TH_OFFS 0x5 /* Thermal Offset; vendor specific */ 70 #define DRAM_MR4_TUF 0x7 /* Temperature Update Flag */ 71 72 #define DRAM_MR4_REFRESH_MASK 0x7 73 #define DRAM_MR4_SR_ABORT_MASK 0x1 74 #define DRAM_MR4_PPRE_MASK 0x1 75 #define DRAM_MR4_TH_OFFS_MASK 0x3 76 #define DRAM_MR4_TUF_MASK 0x1 77 78 /* DRAM Vendor Offsets & Masks */ 79 #define DRAM_VENDOR_MR5 0x0 80 #define DRAM_VENDOR_MR6 0x4 81 #define DRAM_VENDOR_MR7 0x8 82 #define DRAM_VENDOR_MR8 0xc 83 #define DRAM_VENDOR_ERROR 0x10 84 #define DRAM_VENDOR_MASK 0xff 85 86 /* Reset register bits & masks */ 87 #define DCPU_RESET_SHIFT 0x0 88 #define DCPU_RESET_MASK 0x1 89 #define DCPU_CLK_DISABLE_SHIFT 0x2 90 91 /* DCPU return codes */ 92 #define DCPU_RET_ERROR_BIT BIT(31) 93 #define DCPU_RET_SUCCESS 0x1 94 #define DCPU_RET_ERR_HEADER (DCPU_RET_ERROR_BIT | BIT(0)) 95 #define DCPU_RET_ERR_INVAL (DCPU_RET_ERROR_BIT | BIT(1)) 96 #define DCPU_RET_ERR_CHKSUM (DCPU_RET_ERROR_BIT | BIT(2)) 97 #define DCPU_RET_ERR_COMMAND (DCPU_RET_ERROR_BIT | BIT(3)) 98 /* This error code is not firmware defined and only used in the driver. */ 99 #define DCPU_RET_ERR_TIMEDOUT (DCPU_RET_ERROR_BIT | BIT(4)) 100 101 /* Firmware magic */ 102 #define DPFE_BE_MAGIC 0xfe1010fe 103 #define DPFE_LE_MAGIC 0xfe0101fe 104 105 /* Error codes */ 106 #define ERR_INVALID_MAGIC -1 107 #define ERR_INVALID_SIZE -2 108 #define ERR_INVALID_CHKSUM -3 109 110 /* Message types */ 111 #define DPFE_MSG_TYPE_COMMAND 1 112 #define DPFE_MSG_TYPE_RESPONSE 2 113 114 #define DELAY_LOOP_MAX 200000 115 116 enum dpfe_msg_fields { 117 MSG_HEADER, 118 MSG_COMMAND, 119 MSG_ARG_COUNT, 120 MSG_ARG0, 121 MSG_CHKSUM, 122 MSG_FIELD_MAX /* Last entry */ 123 }; 124 125 enum dpfe_commands { 126 DPFE_CMD_GET_INFO, 127 DPFE_CMD_GET_REFRESH, 128 DPFE_CMD_GET_VENDOR, 129 DPFE_CMD_MAX /* Last entry */ 130 }; 131 132 struct dpfe_msg { 133 u32 header; 134 u32 command; 135 u32 arg_count; 136 u32 arg0; 137 u32 chksum; /* This is the sum of all other entries. */ 138 }; 139 140 /* 141 * Format of the binary firmware file: 142 * 143 * entry 144 * 0 header 145 * value: 0xfe0101fe <== little endian 146 * 0xfe1010fe <== big endian 147 * 1 sequence: 148 * [31:16] total segments on this build 149 * [15:0] this segment sequence. 150 * 2 FW version 151 * 3 IMEM byte size 152 * 4 DMEM byte size 153 * IMEM 154 * DMEM 155 * last checksum ==> sum of everything 156 */ 157 struct dpfe_firmware_header { 158 u32 magic; 159 u32 sequence; 160 u32 version; 161 u32 imem_size; 162 u32 dmem_size; 163 }; 164 165 /* Things we only need during initialization. */ 166 struct init_data { 167 unsigned int dmem_len; 168 unsigned int imem_len; 169 unsigned int chksum; 170 bool is_big_endian; 171 }; 172 173 /* Things we need for as long as we are active. */ 174 struct private_data { 175 void __iomem *regs; 176 void __iomem *dmem; 177 void __iomem *imem; 178 struct device *dev; 179 struct mutex lock; 180 }; 181 182 static const char *error_text[] = { 183 "Success", "Header code incorrect", "Unknown command or argument", 184 "Incorrect checksum", "Malformed command", "Timed out", 185 }; 186 187 /* List of supported firmware commands */ 188 static const u32 dpfe_commands[DPFE_CMD_MAX][MSG_FIELD_MAX] = { 189 [DPFE_CMD_GET_INFO] = { 190 [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, 191 [MSG_COMMAND] = 1, 192 [MSG_ARG_COUNT] = 1, 193 [MSG_ARG0] = 1, 194 [MSG_CHKSUM] = 4, 195 }, 196 [DPFE_CMD_GET_REFRESH] = { 197 [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, 198 [MSG_COMMAND] = 2, 199 [MSG_ARG_COUNT] = 1, 200 [MSG_ARG0] = 1, 201 [MSG_CHKSUM] = 5, 202 }, 203 [DPFE_CMD_GET_VENDOR] = { 204 [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, 205 [MSG_COMMAND] = 2, 206 [MSG_ARG_COUNT] = 1, 207 [MSG_ARG0] = 2, 208 [MSG_CHKSUM] = 6, 209 }, 210 }; 211 212 static bool is_dcpu_enabled(void __iomem *regs) 213 { 214 u32 val; 215 216 val = readl_relaxed(regs + REG_DCPU_RESET); 217 218 return !(val & DCPU_RESET_MASK); 219 } 220 221 static void __disable_dcpu(void __iomem *regs) 222 { 223 u32 val; 224 225 if (!is_dcpu_enabled(regs)) 226 return; 227 228 /* Put DCPU in reset if it's running. */ 229 val = readl_relaxed(regs + REG_DCPU_RESET); 230 val |= (1 << DCPU_RESET_SHIFT); 231 writel_relaxed(val, regs + REG_DCPU_RESET); 232 } 233 234 static void __enable_dcpu(void __iomem *regs) 235 { 236 u32 val; 237 238 /* Clear mailbox registers. */ 239 writel_relaxed(0, regs + REG_TO_DCPU_MBOX); 240 writel_relaxed(0, regs + REG_TO_HOST_MBOX); 241 242 /* Disable DCPU clock gating */ 243 val = readl_relaxed(regs + REG_DCPU_RESET); 244 val &= ~(1 << DCPU_CLK_DISABLE_SHIFT); 245 writel_relaxed(val, regs + REG_DCPU_RESET); 246 247 /* Take DCPU out of reset */ 248 val = readl_relaxed(regs + REG_DCPU_RESET); 249 val &= ~(1 << DCPU_RESET_SHIFT); 250 writel_relaxed(val, regs + REG_DCPU_RESET); 251 } 252 253 static unsigned int get_msg_chksum(const u32 msg[]) 254 { 255 unsigned int sum = 0; 256 unsigned int i; 257 258 /* Don't include the last field in the checksum. */ 259 for (i = 0; i < MSG_FIELD_MAX - 1; i++) 260 sum += msg[i]; 261 262 return sum; 263 } 264 265 static void __iomem *get_msg_ptr(struct private_data *priv, u32 response, 266 char *buf, ssize_t *size) 267 { 268 unsigned int msg_type; 269 unsigned int offset; 270 void __iomem *ptr = NULL; 271 272 msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK; 273 offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK; 274 275 /* 276 * msg_type == 1: the offset is relative to the message RAM 277 * msg_type == 0: the offset is relative to the data RAM (this is the 278 * previous way of passing data) 279 * msg_type is anything else: there's critical hardware problem 280 */ 281 switch (msg_type) { 282 case 1: 283 ptr = priv->regs + DCPU_MSG_RAM_START + offset; 284 break; 285 case 0: 286 ptr = priv->dmem + offset; 287 break; 288 default: 289 dev_emerg(priv->dev, "invalid message reply from DCPU: %#x\n", 290 response); 291 if (buf && size) 292 *size = sprintf(buf, 293 "FATAL: communication error with DCPU\n"); 294 } 295 296 return ptr; 297 } 298 299 static int __send_command(struct private_data *priv, unsigned int cmd, 300 u32 result[]) 301 { 302 const u32 *msg = dpfe_commands[cmd]; 303 void __iomem *regs = priv->regs; 304 unsigned int i, chksum; 305 int ret = 0; 306 u32 resp; 307 308 if (cmd >= DPFE_CMD_MAX) 309 return -1; 310 311 mutex_lock(&priv->lock); 312 313 /* Write command and arguments to message area */ 314 for (i = 0; i < MSG_FIELD_MAX; i++) 315 writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i)); 316 317 /* Tell DCPU there is a command waiting */ 318 writel_relaxed(1, regs + REG_TO_DCPU_MBOX); 319 320 /* Wait for DCPU to process the command */ 321 for (i = 0; i < DELAY_LOOP_MAX; i++) { 322 /* Read response code */ 323 resp = readl_relaxed(regs + REG_TO_HOST_MBOX); 324 if (resp > 0) 325 break; 326 udelay(5); 327 } 328 329 if (i == DELAY_LOOP_MAX) { 330 resp = (DCPU_RET_ERR_TIMEDOUT & ~DCPU_RET_ERROR_BIT); 331 ret = -ffs(resp); 332 } else { 333 /* Read response data */ 334 for (i = 0; i < MSG_FIELD_MAX; i++) 335 result[i] = readl_relaxed(regs + DCPU_MSG_RAM(i)); 336 } 337 338 /* Tell DCPU we are done */ 339 writel_relaxed(0, regs + REG_TO_HOST_MBOX); 340 341 mutex_unlock(&priv->lock); 342 343 if (ret) 344 return ret; 345 346 /* Verify response */ 347 chksum = get_msg_chksum(result); 348 if (chksum != result[MSG_CHKSUM]) 349 resp = DCPU_RET_ERR_CHKSUM; 350 351 if (resp != DCPU_RET_SUCCESS) { 352 resp &= ~DCPU_RET_ERROR_BIT; 353 ret = -ffs(resp); 354 } 355 356 return ret; 357 } 358 359 /* Ensure that the firmware file loaded meets all the requirements. */ 360 static int __verify_firmware(struct init_data *init, 361 const struct firmware *fw) 362 { 363 const struct dpfe_firmware_header *header = (void *)fw->data; 364 unsigned int dmem_size, imem_size, total_size; 365 bool is_big_endian = false; 366 const u32 *chksum_ptr; 367 368 if (header->magic == DPFE_BE_MAGIC) 369 is_big_endian = true; 370 else if (header->magic != DPFE_LE_MAGIC) 371 return ERR_INVALID_MAGIC; 372 373 if (is_big_endian) { 374 dmem_size = be32_to_cpu(header->dmem_size); 375 imem_size = be32_to_cpu(header->imem_size); 376 } else { 377 dmem_size = le32_to_cpu(header->dmem_size); 378 imem_size = le32_to_cpu(header->imem_size); 379 } 380 381 /* Data and instruction sections are 32 bit words. */ 382 if ((dmem_size % sizeof(u32)) != 0 || (imem_size % sizeof(u32)) != 0) 383 return ERR_INVALID_SIZE; 384 385 /* 386 * The header + the data section + the instruction section + the 387 * checksum must be equal to the total firmware size. 388 */ 389 total_size = dmem_size + imem_size + sizeof(*header) + 390 sizeof(*chksum_ptr); 391 if (total_size != fw->size) 392 return ERR_INVALID_SIZE; 393 394 /* The checksum comes at the very end. */ 395 chksum_ptr = (void *)fw->data + sizeof(*header) + dmem_size + imem_size; 396 397 init->is_big_endian = is_big_endian; 398 init->dmem_len = dmem_size; 399 init->imem_len = imem_size; 400 init->chksum = (is_big_endian) 401 ? be32_to_cpu(*chksum_ptr) : le32_to_cpu(*chksum_ptr); 402 403 return 0; 404 } 405 406 /* Verify checksum by reading back the firmware from co-processor RAM. */ 407 static int __verify_fw_checksum(struct init_data *init, 408 struct private_data *priv, 409 const struct dpfe_firmware_header *header, 410 u32 checksum) 411 { 412 u32 magic, sequence, version, sum; 413 u32 __iomem *dmem = priv->dmem; 414 u32 __iomem *imem = priv->imem; 415 unsigned int i; 416 417 if (init->is_big_endian) { 418 magic = be32_to_cpu(header->magic); 419 sequence = be32_to_cpu(header->sequence); 420 version = be32_to_cpu(header->version); 421 } else { 422 magic = le32_to_cpu(header->magic); 423 sequence = le32_to_cpu(header->sequence); 424 version = le32_to_cpu(header->version); 425 } 426 427 sum = magic + sequence + version + init->dmem_len + init->imem_len; 428 429 for (i = 0; i < init->dmem_len / sizeof(u32); i++) 430 sum += readl_relaxed(dmem + i); 431 432 for (i = 0; i < init->imem_len / sizeof(u32); i++) 433 sum += readl_relaxed(imem + i); 434 435 return (sum == checksum) ? 0 : -1; 436 } 437 438 static int __write_firmware(u32 __iomem *mem, const u32 *fw, 439 unsigned int size, bool is_big_endian) 440 { 441 unsigned int i; 442 443 /* Convert size to 32-bit words. */ 444 size /= sizeof(u32); 445 446 /* It is recommended to clear the firmware area first. */ 447 for (i = 0; i < size; i++) 448 writel_relaxed(0, mem + i); 449 450 /* Now copy it. */ 451 if (is_big_endian) { 452 for (i = 0; i < size; i++) 453 writel_relaxed(be32_to_cpu(fw[i]), mem + i); 454 } else { 455 for (i = 0; i < size; i++) 456 writel_relaxed(le32_to_cpu(fw[i]), mem + i); 457 } 458 459 return 0; 460 } 461 462 static int brcmstb_dpfe_download_firmware(struct platform_device *pdev, 463 struct init_data *init) 464 { 465 const struct dpfe_firmware_header *header; 466 unsigned int dmem_size, imem_size; 467 struct device *dev = &pdev->dev; 468 bool is_big_endian = false; 469 struct private_data *priv; 470 const struct firmware *fw; 471 const u32 *dmem, *imem; 472 const void *fw_blob; 473 int ret; 474 475 priv = platform_get_drvdata(pdev); 476 477 /* 478 * Skip downloading the firmware if the DCPU is already running and 479 * responding to commands. 480 */ 481 if (is_dcpu_enabled(priv->regs)) { 482 u32 response[MSG_FIELD_MAX]; 483 484 ret = __send_command(priv, DPFE_CMD_GET_INFO, response); 485 if (!ret) 486 return 0; 487 } 488 489 ret = request_firmware(&fw, FIRMWARE_NAME, dev); 490 /* request_firmware() prints its own error messages. */ 491 if (ret) 492 return ret; 493 494 ret = __verify_firmware(init, fw); 495 if (ret) 496 return -EFAULT; 497 498 __disable_dcpu(priv->regs); 499 500 is_big_endian = init->is_big_endian; 501 dmem_size = init->dmem_len; 502 imem_size = init->imem_len; 503 504 /* At the beginning of the firmware blob is a header. */ 505 header = (struct dpfe_firmware_header *)fw->data; 506 /* Void pointer to the beginning of the actual firmware. */ 507 fw_blob = fw->data + sizeof(*header); 508 /* IMEM comes right after the header. */ 509 imem = fw_blob; 510 /* DMEM follows after IMEM. */ 511 dmem = fw_blob + imem_size; 512 513 ret = __write_firmware(priv->dmem, dmem, dmem_size, is_big_endian); 514 if (ret) 515 return ret; 516 ret = __write_firmware(priv->imem, imem, imem_size, is_big_endian); 517 if (ret) 518 return ret; 519 520 ret = __verify_fw_checksum(init, priv, header, init->chksum); 521 if (ret) 522 return ret; 523 524 __enable_dcpu(priv->regs); 525 526 return 0; 527 } 528 529 static ssize_t generic_show(unsigned int command, u32 response[], 530 struct device *dev, char *buf) 531 { 532 struct private_data *priv; 533 int ret; 534 535 priv = dev_get_drvdata(dev); 536 if (!priv) 537 return sprintf(buf, "ERROR: driver private data not set\n"); 538 539 ret = __send_command(priv, command, response); 540 if (ret < 0) 541 return sprintf(buf, "ERROR: %s\n", error_text[-ret]); 542 543 return 0; 544 } 545 546 static ssize_t show_info(struct device *dev, struct device_attribute *devattr, 547 char *buf) 548 { 549 u32 response[MSG_FIELD_MAX]; 550 unsigned int info; 551 ssize_t ret; 552 553 ret = generic_show(DPFE_CMD_GET_INFO, response, dev, buf); 554 if (ret) 555 return ret; 556 557 info = response[MSG_ARG0]; 558 559 return sprintf(buf, "%u.%u.%u.%u\n", 560 (info >> 24) & 0xff, 561 (info >> 16) & 0xff, 562 (info >> 8) & 0xff, 563 info & 0xff); 564 } 565 566 static ssize_t show_refresh(struct device *dev, 567 struct device_attribute *devattr, char *buf) 568 { 569 u32 response[MSG_FIELD_MAX]; 570 void __iomem *info; 571 struct private_data *priv; 572 u8 refresh, sr_abort, ppre, thermal_offs, tuf; 573 u32 mr4; 574 ssize_t ret; 575 576 ret = generic_show(DPFE_CMD_GET_REFRESH, response, dev, buf); 577 if (ret) 578 return ret; 579 580 priv = dev_get_drvdata(dev); 581 582 info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret); 583 if (!info) 584 return ret; 585 586 mr4 = readl_relaxed(info + DRAM_INFO_MR4) & DRAM_INFO_MR4_MASK; 587 588 refresh = (mr4 >> DRAM_MR4_REFRESH) & DRAM_MR4_REFRESH_MASK; 589 sr_abort = (mr4 >> DRAM_MR4_SR_ABORT) & DRAM_MR4_SR_ABORT_MASK; 590 ppre = (mr4 >> DRAM_MR4_PPRE) & DRAM_MR4_PPRE_MASK; 591 thermal_offs = (mr4 >> DRAM_MR4_TH_OFFS) & DRAM_MR4_TH_OFFS_MASK; 592 tuf = (mr4 >> DRAM_MR4_TUF) & DRAM_MR4_TUF_MASK; 593 594 return sprintf(buf, "%#x %#x %#x %#x %#x %#x %#x\n", 595 readl_relaxed(info + DRAM_INFO_INTERVAL), 596 refresh, sr_abort, ppre, thermal_offs, tuf, 597 readl_relaxed(info + DRAM_INFO_ERROR)); 598 } 599 600 static ssize_t store_refresh(struct device *dev, struct device_attribute *attr, 601 const char *buf, size_t count) 602 { 603 u32 response[MSG_FIELD_MAX]; 604 struct private_data *priv; 605 void __iomem *info; 606 unsigned long val; 607 int ret; 608 609 if (kstrtoul(buf, 0, &val) < 0) 610 return -EINVAL; 611 612 priv = dev_get_drvdata(dev); 613 614 ret = __send_command(priv, DPFE_CMD_GET_REFRESH, response); 615 if (ret) 616 return ret; 617 618 info = get_msg_ptr(priv, response[MSG_ARG0], NULL, NULL); 619 if (!info) 620 return -EIO; 621 622 writel_relaxed(val, info + DRAM_INFO_INTERVAL); 623 624 return count; 625 } 626 627 static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr, 628 char *buf) 629 { 630 u32 response[MSG_FIELD_MAX]; 631 struct private_data *priv; 632 void __iomem *info; 633 ssize_t ret; 634 635 ret = generic_show(DPFE_CMD_GET_VENDOR, response, dev, buf); 636 if (ret) 637 return ret; 638 639 priv = dev_get_drvdata(dev); 640 641 info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret); 642 if (!info) 643 return ret; 644 645 return sprintf(buf, "%#x %#x %#x %#x %#x\n", 646 readl_relaxed(info + DRAM_VENDOR_MR5) & DRAM_VENDOR_MASK, 647 readl_relaxed(info + DRAM_VENDOR_MR6) & DRAM_VENDOR_MASK, 648 readl_relaxed(info + DRAM_VENDOR_MR7) & DRAM_VENDOR_MASK, 649 readl_relaxed(info + DRAM_VENDOR_MR8) & DRAM_VENDOR_MASK, 650 readl_relaxed(info + DRAM_VENDOR_ERROR) & 651 DRAM_VENDOR_MASK); 652 } 653 654 static int brcmstb_dpfe_resume(struct platform_device *pdev) 655 { 656 struct init_data init; 657 658 return brcmstb_dpfe_download_firmware(pdev, &init); 659 } 660 661 static DEVICE_ATTR(dpfe_info, 0444, show_info, NULL); 662 static DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh); 663 static DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL); 664 static struct attribute *dpfe_attrs[] = { 665 &dev_attr_dpfe_info.attr, 666 &dev_attr_dpfe_refresh.attr, 667 &dev_attr_dpfe_vendor.attr, 668 NULL 669 }; 670 ATTRIBUTE_GROUPS(dpfe); 671 672 static int brcmstb_dpfe_probe(struct platform_device *pdev) 673 { 674 struct device *dev = &pdev->dev; 675 struct private_data *priv; 676 struct init_data init; 677 struct resource *res; 678 int ret; 679 680 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 681 if (!priv) 682 return -ENOMEM; 683 684 mutex_init(&priv->lock); 685 platform_set_drvdata(pdev, priv); 686 687 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpfe-cpu"); 688 priv->regs = devm_ioremap_resource(dev, res); 689 if (IS_ERR(priv->regs)) { 690 dev_err(dev, "couldn't map DCPU registers\n"); 691 return -ENODEV; 692 } 693 694 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpfe-dmem"); 695 priv->dmem = devm_ioremap_resource(dev, res); 696 if (IS_ERR(priv->dmem)) { 697 dev_err(dev, "Couldn't map DCPU data memory\n"); 698 return -ENOENT; 699 } 700 701 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpfe-imem"); 702 priv->imem = devm_ioremap_resource(dev, res); 703 if (IS_ERR(priv->imem)) { 704 dev_err(dev, "Couldn't map DCPU instruction memory\n"); 705 return -ENOENT; 706 } 707 708 ret = brcmstb_dpfe_download_firmware(pdev, &init); 709 if (ret) 710 return ret; 711 712 ret = sysfs_create_groups(&pdev->dev.kobj, dpfe_groups); 713 if (!ret) 714 dev_info(dev, "registered.\n"); 715 716 return ret; 717 } 718 719 static int brcmstb_dpfe_remove(struct platform_device *pdev) 720 { 721 sysfs_remove_groups(&pdev->dev.kobj, dpfe_groups); 722 723 return 0; 724 } 725 726 static const struct of_device_id brcmstb_dpfe_of_match[] = { 727 { .compatible = "brcm,dpfe-cpu", }, 728 {} 729 }; 730 MODULE_DEVICE_TABLE(of, brcmstb_dpfe_of_match); 731 732 static struct platform_driver brcmstb_dpfe_driver = { 733 .driver = { 734 .name = DRVNAME, 735 .of_match_table = brcmstb_dpfe_of_match, 736 }, 737 .probe = brcmstb_dpfe_probe, 738 .remove = brcmstb_dpfe_remove, 739 .resume = brcmstb_dpfe_resume, 740 }; 741 742 module_platform_driver(brcmstb_dpfe_driver); 743 744 MODULE_AUTHOR("Markus Mayer <mmayer@broadcom.com>"); 745 MODULE_DESCRIPTION("BRCMSTB DDR PHY Front End Driver"); 746 MODULE_LICENSE("GPL"); 747