Commit 05ec260edecaf3dc214cff49d43b1ad9b2cbb710

Authored by Linus Walleij
1 parent f25610ce53

mfd: db8500-prcmu: update resource passing

When trying to get rid of the cross-includes of <mach/id.h>
from different drivers, so we can localize ASIC/CPU detection
to the mach-ux500 folder, we run into the way the PRCMU
handles base addresses and firmware detection.

This patch updates the firmware version detection to pass
the required information as platform data instead of
relying on cpu_is_* macros.

Now the PRCMU base address, the secondary TCDM area, the
TCPM area and the IRQ are passed as resources instead of
being grabbed from <mach/*> files. Incidentally this also
removes part of the reliance on <mach/irqs.h>.

Further it updates the firmware version detection, since the
location of the firmware ID bytes in the designated memory
are is now passed from the platform data instead. There is
no reason not to include the nice split-off of a struct to
hold the firmware information and a separate function to
populate it.

The patch actually rids the need to use the external
db8500_prcmu_early_init call at all, but I'm keepin back
that removal as I don't want the patch to be too big.

Cc: arm@kernel.org
Cc: Michel Jaoen <michel.jaouen@stericsson.com>
Cc: Lee Jones <lee.jones@linaro.org>
Acked-by: Samuel Ortiz <sameo@linux.intel.com>
Acked-by: Loic Pallardy <loic.pallardy@stericsson.com>
Acked-by: Fabio Baltieri <fabio.baltieri@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Showing 7 changed files with 180 additions and 63 deletions Side-by-side Diff

arch/arm/mach-ux500/board-mop500.c
... ... @@ -215,7 +215,7 @@
215 215 },
216 216 };
217 217  
218   -static struct ab8500_platform_data ab8500_platdata = {
  218 +struct ab8500_platform_data ab8500_platdata = {
219 219 .irq_base = MOP500_AB8500_IRQ_BASE,
220 220 .regulator_reg_init = ab8500_regulator_reg_init,
221 221 .num_regulator_reg_init = ARRAY_SIZE(ab8500_regulator_reg_init),
... ... @@ -651,6 +651,7 @@
651 651 int i2c0_devs;
652 652 int i;
653 653  
  654 + platform_device_register(&db8500_prcmu_device);
654 655 mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
655 656  
656 657 mop500_pinmaps_init();
... ... @@ -685,6 +686,7 @@
685 686 struct device *parent = NULL;
686 687 int i;
687 688  
  689 + platform_device_register(&db8500_prcmu_device);
688 690 snowball_pinmaps_init();
689 691 parent = u8500_init_devices(&ab8500_platdata);
690 692  
... ... @@ -710,6 +712,7 @@
710 712 int i2c0_devs;
711 713 int i;
712 714  
  715 + platform_device_register(&db8500_prcmu_device);
713 716 /*
714 717 * The HREFv60 board removed a GPIO expander and routed
715 718 * all these GPIO pins to the internal GPIO controller
arch/arm/mach-ux500/cpu-db8500.c
... ... @@ -139,14 +139,9 @@
139 139 .dev.platform_data = &db8500_pmu_platdata,
140 140 };
141 141  
142   -static struct platform_device db8500_prcmu_device = {
143   - .name = "db8500-prcmu",
144   -};
145   -
146 142 static struct platform_device *platform_devs[] __initdata = {
147 143 &u8500_dma40_device,
148 144 &db8500_pmu_device,
149   - &db8500_prcmu_device,
150 145 };
151 146  
152 147 static resource_size_t __initdata db8500_gpio_base[] = {
... ... @@ -286,6 +281,8 @@
286 281 OF_DEV_AUXDATA("st,nomadik-i2c", 0x80128000, "nmk-i2c.2", NULL),
287 282 OF_DEV_AUXDATA("st,nomadik-i2c", 0x80110000, "nmk-i2c.3", NULL),
288 283 OF_DEV_AUXDATA("st,nomadik-i2c", 0x8012a000, "nmk-i2c.4", NULL),
  284 + OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu",
  285 + &db8500_prcmu_pdata),
289 286 /* Requires device name bindings. */
290 287 OF_DEV_AUXDATA("stericsson,nmk_pinctrl", 0, "pinctrl-db8500", NULL),
291 288 /* Requires clock name and DMA bindings. */
arch/arm/mach-ux500/devices-db8500.c
... ... @@ -13,11 +13,13 @@
13 13 #include <linux/amba/bus.h>
14 14 #include <linux/amba/pl022.h>
15 15 #include <linux/platform_data/dma-ste-dma40.h>
  16 +#include <linux/mfd/dbx500-prcmu.h>
16 17  
17 18 #include <mach/hardware.h>
18 19 #include <mach/setup.h>
19 20 #include <mach/irqs.h>
20 21  
  22 +#include "devices-db8500.h"
21 23 #include "ste-dma40-db8500.h"
22 24  
23 25 static struct resource dma40_resources[] = {
... ... @@ -193,5 +195,47 @@
193 195 .id = -1,
194 196 .num_resources = ARRAY_SIZE(keypad_resources),
195 197 .resource = keypad_resources,
  198 +};
  199 +
  200 +struct prcmu_pdata db8500_prcmu_pdata = {
  201 + .ab_platdata = &ab8500_platdata,
  202 + .version_offset = DB8500_PRCMU_FW_VERSION_OFFSET,
  203 + .legacy_offset = DB8500_PRCMU_LEGACY_OFFSET,
  204 +};
  205 +
  206 +static struct resource db8500_prcmu_res[] = {
  207 + {
  208 + .name = "prcmu",
  209 + .start = U8500_PRCMU_BASE,
  210 + .end = U8500_PRCMU_BASE + SZ_8K - 1,
  211 + .flags = IORESOURCE_MEM,
  212 + },
  213 + {
  214 + .name = "prcmu-tcdm",
  215 + .start = U8500_PRCMU_TCDM_BASE,
  216 + .end = U8500_PRCMU_TCDM_BASE + SZ_4K - 1,
  217 + .flags = IORESOURCE_MEM,
  218 + },
  219 + {
  220 + .name = "irq",
  221 + .start = IRQ_DB8500_PRCMU1,
  222 + .end = IRQ_DB8500_PRCMU1,
  223 + .flags = IORESOURCE_IRQ,
  224 + },
  225 + {
  226 + .name = "prcmu-tcpm",
  227 + .start = U8500_PRCMU_TCPM_BASE,
  228 + .end = U8500_PRCMU_TCPM_BASE + SZ_4K - 1,
  229 + .flags = IORESOURCE_MEM,
  230 + },
  231 +};
  232 +
  233 +struct platform_device db8500_prcmu_device = {
  234 + .name = "db8500-prcmu",
  235 + .resource = db8500_prcmu_res,
  236 + .num_resources = ARRAY_SIZE(db8500_prcmu_res),
  237 + .dev = {
  238 + .platform_data = &db8500_prcmu_pdata,
  239 + },
196 240 };
arch/arm/mach-ux500/devices-db8500.h
... ... @@ -14,6 +14,11 @@
14 14  
15 15 struct ske_keypad_platform_data;
16 16 struct pl022_ssp_controller;
  17 +struct platform_device;
  18 +
  19 +extern struct ab8500_platform_data ab8500_platdata;
  20 +extern struct prcmu_pdata db8500_prcmu_pdata;
  21 +extern struct platform_device db8500_prcmu_device;
17 22  
18 23 static inline struct platform_device *
19 24 db8500_add_ske_keypad(struct device *parent,
drivers/mfd/db8500-prcmu.c
... ... @@ -38,9 +38,6 @@
38 38 #include <mach/db8500-regs.h>
39 39 #include "dbx500-prcmu-regs.h"
40 40  
41   -/* Offset for the firmware version within the TCPM */
42   -#define PRCMU_FW_VERSION_OFFSET 0xA4
43   -
44 41 /* Index of different voltages to be used when accessing AVSData */
45 42 #define PRCM_AVS_BASE 0x2FC
46 43 #define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0)
47 44  
48 45  
49 46  
50 47  
... ... @@ -2704,21 +2701,43 @@
2704 2701 .irq_unmask = prcmu_irq_unmask,
2705 2702 };
2706 2703  
2707   -static char *fw_project_name(u8 project)
  2704 +static __init char *fw_project_name(u32 project)
2708 2705 {
2709 2706 switch (project) {
2710 2707 case PRCMU_FW_PROJECT_U8500:
2711 2708 return "U8500";
2712   - case PRCMU_FW_PROJECT_U8500_C2:
2713   - return "U8500 C2";
  2709 + case PRCMU_FW_PROJECT_U8400:
  2710 + return "U8400";
2714 2711 case PRCMU_FW_PROJECT_U9500:
2715 2712 return "U9500";
2716   - case PRCMU_FW_PROJECT_U9500_C2:
2717   - return "U9500 C2";
  2713 + case PRCMU_FW_PROJECT_U8500_MBB:
  2714 + return "U8500 MBB";
  2715 + case PRCMU_FW_PROJECT_U8500_C1:
  2716 + return "U8500 C1";
  2717 + case PRCMU_FW_PROJECT_U8500_C2:
  2718 + return "U8500 C2";
  2719 + case PRCMU_FW_PROJECT_U8500_C3:
  2720 + return "U8500 C3";
  2721 + case PRCMU_FW_PROJECT_U8500_C4:
  2722 + return "U8500 C4";
  2723 + case PRCMU_FW_PROJECT_U9500_MBL:
  2724 + return "U9500 MBL";
  2725 + case PRCMU_FW_PROJECT_U8500_MBL:
  2726 + return "U8500 MBL";
  2727 + case PRCMU_FW_PROJECT_U8500_MBL2:
  2728 + return "U8500 MBL2";
2718 2729 case PRCMU_FW_PROJECT_U8520:
2719   - return "U8520";
  2730 + return "U8520 MBL";
2720 2731 case PRCMU_FW_PROJECT_U8420:
2721 2732 return "U8420";
  2733 + case PRCMU_FW_PROJECT_U9540:
  2734 + return "U9540";
  2735 + case PRCMU_FW_PROJECT_A9420:
  2736 + return "A9420";
  2737 + case PRCMU_FW_PROJECT_L8540:
  2738 + return "L8540";
  2739 + case PRCMU_FW_PROJECT_L8580:
  2740 + return "L8580";
2722 2741 default:
2723 2742 return "Unknown";
2724 2743 }
2725 2744  
2726 2745  
2727 2746  
2728 2747  
2729 2748  
... ... @@ -2759,37 +2778,44 @@
2759 2778 return 0;
2760 2779 }
2761 2780  
2762   -void __init db8500_prcmu_early_init(void)
  2781 +static void dbx500_fw_version_init(struct platform_device *pdev,
  2782 + u32 version_offset)
2763 2783 {
2764   - if (cpu_is_u8500v2() || cpu_is_u9540()) {
2765   - void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
  2784 + struct resource *res;
  2785 + void __iomem *tcpm_base;
2766 2786  
2767   - if (tcpm_base != NULL) {
2768   - u32 version;
2769   - version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
2770   - fw_info.version.project = version & 0xFF;
2771   - fw_info.version.api_version = (version >> 8) & 0xFF;
2772   - fw_info.version.func_version = (version >> 16) & 0xFF;
2773   - fw_info.version.errata = (version >> 24) & 0xFF;
2774   - fw_info.valid = true;
2775   - pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
2776   - fw_project_name(fw_info.version.project),
2777   - (version >> 8) & 0xFF, (version >> 16) & 0xFF,
2778   - (version >> 24) & 0xFF);
2779   - iounmap(tcpm_base);
2780   - }
  2787 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
  2788 + "prcmu-tcpm");
  2789 + if (!res) {
  2790 + dev_err(&pdev->dev,
  2791 + "Error: no prcmu tcpm memory region provided\n");
  2792 + return;
  2793 + }
  2794 + tcpm_base = ioremap(res->start, resource_size(res));
  2795 + if (tcpm_base != NULL) {
  2796 + u32 version;
2781 2797  
2782   - if (cpu_is_u9540())
2783   - tcdm_base = ioremap_nocache(U8500_PRCMU_TCDM_BASE,
2784   - SZ_4K + SZ_8K) + SZ_8K;
2785   - else
2786   - tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
2787   - } else {
2788   - pr_err("prcmu: Unsupported chip version\n");
2789   - BUG();
  2798 + version = readl(tcpm_base + version_offset);
  2799 + fw_info.version.project = (version & 0xFF);
  2800 + fw_info.version.api_version = (version >> 8) & 0xFF;
  2801 + fw_info.version.func_version = (version >> 16) & 0xFF;
  2802 + fw_info.version.errata = (version >> 24) & 0xFF;
  2803 + strncpy(fw_info.version.project_name,
  2804 + fw_project_name(fw_info.version.project),
  2805 + PRCMU_FW_PROJECT_NAME_LEN);
  2806 + fw_info.valid = true;
  2807 + pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n",
  2808 + fw_info.version.project_name,
  2809 + fw_info.version.project,
  2810 + fw_info.version.api_version,
  2811 + fw_info.version.func_version,
  2812 + fw_info.version.errata);
  2813 + iounmap(tcpm_base);
2790 2814 }
2791   - tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
  2815 +}
2792 2816  
  2817 +void __init db8500_prcmu_early_init(void)
  2818 +{
2793 2819 spin_lock_init(&mb0_transfer.lock);
2794 2820 spin_lock_init(&mb0_transfer.dbb_irqs_lock);
2795 2821 mutex_init(&mb0_transfer.ac_wake_lock);
2796 2822  
2797 2823  
2798 2824  
2799 2825  
2800 2826  
... ... @@ -3099,21 +3125,31 @@
3099 3125 */
3100 3126 static int db8500_prcmu_probe(struct platform_device *pdev)
3101 3127 {
3102   - struct ab8500_platform_data *ab8500_platdata = pdev->dev.platform_data;
3103 3128 struct device_node *np = pdev->dev.of_node;
  3129 + struct prcmu_pdata *pdata = dev_get_platdata(&pdev->dev);
3104 3130 int irq = 0, err = 0, i;
  3131 + struct resource *res;
3105 3132  
3106 3133 init_prcm_registers();
3107 3134  
  3135 + dbx500_fw_version_init(pdev, pdata->version_offset);
  3136 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
  3137 + if (!res) {
  3138 + dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
  3139 + return -ENOENT;
  3140 + }
  3141 + tcdm_base = devm_ioremap(&pdev->dev, res->start,
  3142 + resource_size(res));
  3143 +
3108 3144 /* Clean up the mailbox interrupts after pre-kernel code. */
3109 3145 writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
3110 3146  
3111   - if (np)
3112   - irq = platform_get_irq(pdev, 0);
  3147 + irq = platform_get_irq(pdev, 0);
  3148 + if (irq <= 0) {
  3149 + dev_err(&pdev->dev, "no prcmu irq provided\n");
  3150 + return -ENOENT;
  3151 + }
3113 3152  
3114   - if (!np || irq <= 0)
3115   - irq = IRQ_DB8500_PRCMU1;
3116   -
3117 3153 err = request_threaded_irq(irq, prcmu_irq_handler,
3118 3154 prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
3119 3155 if (err < 0) {
... ... @@ -3126,7 +3162,7 @@
3126 3162  
3127 3163 for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) {
3128 3164 if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) {
3129   - db8500_prcmu_devs[i].platform_data = ab8500_platdata;
  3165 + db8500_prcmu_devs[i].platform_data = pdata->ab_platdata;
3130 3166 db8500_prcmu_devs[i].pdata_size = sizeof(struct ab8500_platform_data);
3131 3167 }
3132 3168 }
include/linux/mfd/db8500-prcmu.h
... ... @@ -487,20 +487,6 @@
487 487 u8 sva_policy;
488 488 };
489 489  
490   -#define PRCMU_FW_PROJECT_U8500 2
491   -#define PRCMU_FW_PROJECT_U9500 4
492   -#define PRCMU_FW_PROJECT_U8500_C2 7
493   -#define PRCMU_FW_PROJECT_U9500_C2 11
494   -#define PRCMU_FW_PROJECT_U8520 13
495   -#define PRCMU_FW_PROJECT_U8420 14
496   -
497   -struct prcmu_fw_version {
498   - u8 project;
499   - u8 api_version;
500   - u8 func_version;
501   - u8 errata;
502   -};
503   -
504 490 #ifdef CONFIG_MFD_DB8500_PRCMU
505 491  
506 492 void db8500_prcmu_early_init(void);
include/linux/mfd/dbx500-prcmu.h
... ... @@ -12,6 +12,10 @@
12 12 #include <linux/notifier.h>
13 13 #include <linux/err.h>
14 14  
  15 +/* Offset for the firmware version within the TCPM */
  16 +#define DB8500_PRCMU_FW_VERSION_OFFSET 0xA4
  17 +#define DBX540_PRCMU_FW_VERSION_OFFSET 0xA8
  18 +
15 19 /* PRCMU Wakeup defines */
16 20 enum prcmu_wakeup_index {
17 21 PRCMU_WAKEUP_INDEX_RTC,
... ... @@ -212,6 +216,48 @@
212 216 DDR_PWR_STATE_ON = 0x01,
213 217 DDR_PWR_STATE_OFFLOWLAT = 0x02,
214 218 DDR_PWR_STATE_OFFHIGHLAT = 0x03
  219 +};
  220 +
  221 +#define DB8500_PRCMU_LEGACY_OFFSET 0xDD4
  222 +
  223 +struct prcmu_pdata
  224 +{
  225 + bool enable_set_ddr_opp;
  226 + bool enable_ape_opp_100_voltage;
  227 + struct ab8500_platform_data *ab_platdata;
  228 + u32 version_offset;
  229 + u32 legacy_offset;
  230 + u32 adt_offset;
  231 +};
  232 +
  233 +#define PRCMU_FW_PROJECT_U8500 2
  234 +#define PRCMU_FW_PROJECT_U8400 3
  235 +#define PRCMU_FW_PROJECT_U9500 4 /* Customer specific */
  236 +#define PRCMU_FW_PROJECT_U8500_MBB 5
  237 +#define PRCMU_FW_PROJECT_U8500_C1 6
  238 +#define PRCMU_FW_PROJECT_U8500_C2 7
  239 +#define PRCMU_FW_PROJECT_U8500_C3 8
  240 +#define PRCMU_FW_PROJECT_U8500_C4 9
  241 +#define PRCMU_FW_PROJECT_U9500_MBL 10
  242 +#define PRCMU_FW_PROJECT_U8500_MBL 11 /* Customer specific */
  243 +#define PRCMU_FW_PROJECT_U8500_MBL2 12 /* Customer specific */
  244 +#define PRCMU_FW_PROJECT_U8520 13
  245 +#define PRCMU_FW_PROJECT_U8420 14
  246 +#define PRCMU_FW_PROJECT_A9420 20
  247 +/* [32..63] 9540 and derivatives */
  248 +#define PRCMU_FW_PROJECT_U9540 32
  249 +/* [64..95] 8540 and derivatives */
  250 +#define PRCMU_FW_PROJECT_L8540 64
  251 +/* [96..126] 8580 and derivatives */
  252 +#define PRCMU_FW_PROJECT_L8580 96
  253 +
  254 +#define PRCMU_FW_PROJECT_NAME_LEN 20
  255 +struct prcmu_fw_version {
  256 + u32 project; /* Notice, project shifted with 8 on ux540 */
  257 + u8 api_version;
  258 + u8 func_version;
  259 + u8 errata;
  260 + char project_name[PRCMU_FW_PROJECT_NAME_LEN];
215 261 };
216 262  
217 263 #include <linux/mfd/db8500-prcmu.h>