0001
0002
0003
0004
0005
0006
0007
0008 #include <dt-bindings/soc/bcm2835-pm.h>
0009 #include <linux/clk.h>
0010 #include <linux/delay.h>
0011 #include <linux/io.h>
0012 #include <linux/mfd/bcm2835-pm.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/pm_domain.h>
0016 #include <linux/reset-controller.h>
0017 #include <linux/types.h>
0018
0019 #define PM_GNRIC 0x00
0020 #define PM_AUDIO 0x04
0021 #define PM_STATUS 0x18
0022 #define PM_RSTC 0x1c
0023 #define PM_RSTS 0x20
0024 #define PM_WDOG 0x24
0025 #define PM_PADS0 0x28
0026 #define PM_PADS2 0x2c
0027 #define PM_PADS3 0x30
0028 #define PM_PADS4 0x34
0029 #define PM_PADS5 0x38
0030 #define PM_PADS6 0x3c
0031 #define PM_CAM0 0x44
0032 #define PM_CAM0_LDOHPEN BIT(2)
0033 #define PM_CAM0_LDOLPEN BIT(1)
0034 #define PM_CAM0_CTRLEN BIT(0)
0035
0036 #define PM_CAM1 0x48
0037 #define PM_CAM1_LDOHPEN BIT(2)
0038 #define PM_CAM1_LDOLPEN BIT(1)
0039 #define PM_CAM1_CTRLEN BIT(0)
0040
0041 #define PM_CCP2TX 0x4c
0042 #define PM_CCP2TX_LDOEN BIT(1)
0043 #define PM_CCP2TX_CTRLEN BIT(0)
0044
0045 #define PM_DSI0 0x50
0046 #define PM_DSI0_LDOHPEN BIT(2)
0047 #define PM_DSI0_LDOLPEN BIT(1)
0048 #define PM_DSI0_CTRLEN BIT(0)
0049
0050 #define PM_DSI1 0x54
0051 #define PM_DSI1_LDOHPEN BIT(2)
0052 #define PM_DSI1_LDOLPEN BIT(1)
0053 #define PM_DSI1_CTRLEN BIT(0)
0054
0055 #define PM_HDMI 0x58
0056 #define PM_HDMI_RSTDR BIT(19)
0057 #define PM_HDMI_LDOPD BIT(1)
0058 #define PM_HDMI_CTRLEN BIT(0)
0059
0060 #define PM_USB 0x5c
0061
0062
0063
0064 #define PM_USB_CTRLEN BIT(0)
0065
0066 #define PM_PXLDO 0x60
0067 #define PM_PXBG 0x64
0068 #define PM_DFT 0x68
0069 #define PM_SMPS 0x6c
0070 #define PM_XOSC 0x70
0071 #define PM_SPAREW 0x74
0072 #define PM_SPARER 0x78
0073 #define PM_AVS_RSTDR 0x7c
0074 #define PM_AVS_STAT 0x80
0075 #define PM_AVS_EVENT 0x84
0076 #define PM_AVS_INTEN 0x88
0077 #define PM_DUMMY 0xfc
0078
0079 #define PM_IMAGE 0x108
0080 #define PM_GRAFX 0x10c
0081 #define PM_PROC 0x110
0082 #define PM_ENAB BIT(12)
0083 #define PM_ISPRSTN BIT(8)
0084 #define PM_H264RSTN BIT(7)
0085 #define PM_PERIRSTN BIT(6)
0086 #define PM_V3DRSTN BIT(6)
0087 #define PM_ISFUNC BIT(5)
0088 #define PM_MRDONE BIT(4)
0089 #define PM_MEMREP BIT(3)
0090 #define PM_ISPOW BIT(2)
0091 #define PM_POWOK BIT(1)
0092 #define PM_POWUP BIT(0)
0093 #define PM_INRUSH_SHIFT 13
0094 #define PM_INRUSH_3_5_MA 0
0095 #define PM_INRUSH_5_MA 1
0096 #define PM_INRUSH_10_MA 2
0097 #define PM_INRUSH_20_MA 3
0098 #define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT)
0099
0100 #define PM_PASSWORD 0x5a000000
0101
0102 #define PM_WDOG_TIME_SET 0x000fffff
0103 #define PM_RSTC_WRCFG_CLR 0xffffffcf
0104 #define PM_RSTS_HADWRH_SET 0x00000040
0105 #define PM_RSTC_WRCFG_SET 0x00000030
0106 #define PM_RSTC_WRCFG_FULL_RESET 0x00000020
0107 #define PM_RSTC_RESET 0x00000102
0108
0109 #define PM_READ(reg) readl(power->base + (reg))
0110 #define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
0111
0112 #define ASB_BRDG_VERSION 0x00
0113 #define ASB_CPR_CTRL 0x04
0114
0115 #define ASB_V3D_S_CTRL 0x08
0116 #define ASB_V3D_M_CTRL 0x0c
0117 #define ASB_ISP_S_CTRL 0x10
0118 #define ASB_ISP_M_CTRL 0x14
0119 #define ASB_H264_S_CTRL 0x18
0120 #define ASB_H264_M_CTRL 0x1c
0121
0122 #define ASB_REQ_STOP BIT(0)
0123 #define ASB_ACK BIT(1)
0124 #define ASB_EMPTY BIT(2)
0125 #define ASB_FULL BIT(3)
0126
0127 #define ASB_AXI_BRDG_ID 0x20
0128
0129 #define BCM2835_BRDG_ID 0x62726467
0130
0131 struct bcm2835_power_domain {
0132 struct generic_pm_domain base;
0133 struct bcm2835_power *power;
0134 u32 domain;
0135 struct clk *clk;
0136 };
0137
0138 struct bcm2835_power {
0139 struct device *dev;
0140
0141 void __iomem *base;
0142
0143 void __iomem *asb;
0144
0145 void __iomem *rpivid_asb;
0146
0147 struct genpd_onecell_data pd_xlate;
0148 struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
0149 struct reset_controller_dev reset;
0150 };
0151
0152 static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
0153 {
0154 void __iomem *base = power->asb;
0155 u64 start;
0156 u32 val;
0157
0158 switch (reg) {
0159 case 0:
0160 return 0;
0161 case ASB_V3D_S_CTRL:
0162 case ASB_V3D_M_CTRL:
0163 if (power->rpivid_asb)
0164 base = power->rpivid_asb;
0165 break;
0166 }
0167
0168 start = ktime_get_ns();
0169
0170
0171 if (enable) {
0172 val = readl(base + reg) & ~ASB_REQ_STOP;
0173 } else {
0174 val = readl(base + reg) | ASB_REQ_STOP;
0175 }
0176 writel(PM_PASSWORD | val, base + reg);
0177
0178 while (readl(base + reg) & ASB_ACK) {
0179 cpu_relax();
0180 if (ktime_get_ns() - start >= 1000)
0181 return -ETIMEDOUT;
0182 }
0183
0184 return 0;
0185 }
0186
0187 static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
0188 {
0189 return bcm2835_asb_control(power, reg, true);
0190 }
0191
0192 static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
0193 {
0194 return bcm2835_asb_control(power, reg, false);
0195 }
0196
0197 static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
0198 {
0199 struct bcm2835_power *power = pd->power;
0200
0201
0202 if (power->rpivid_asb)
0203 return 0;
0204
0205
0206 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
0207
0208
0209 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
0210
0211
0212 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
0213
0214 return 0;
0215 }
0216
0217 static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
0218 {
0219 struct bcm2835_power *power = pd->power;
0220 struct device *dev = power->dev;
0221 u64 start;
0222 int ret;
0223 int inrush;
0224 bool powok;
0225
0226
0227 if (power->rpivid_asb)
0228 return 0;
0229
0230
0231 if (PM_READ(pm_reg) & PM_POWUP)
0232 return 0;
0233
0234
0235
0236
0237
0238 powok = false;
0239 for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
0240 PM_WRITE(pm_reg,
0241 (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
0242 (inrush << PM_INRUSH_SHIFT) |
0243 PM_POWUP);
0244
0245 start = ktime_get_ns();
0246 while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
0247 cpu_relax();
0248 if (ktime_get_ns() - start >= 3000)
0249 break;
0250 }
0251 }
0252 if (!powok) {
0253 dev_err(dev, "Timeout waiting for %s power OK\n",
0254 pd->base.name);
0255 ret = -ETIMEDOUT;
0256 goto err_disable_powup;
0257 }
0258
0259
0260 PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
0261
0262
0263 PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
0264 start = ktime_get_ns();
0265 while (!(PM_READ(pm_reg) & PM_MRDONE)) {
0266 cpu_relax();
0267 if (ktime_get_ns() - start >= 1000) {
0268 dev_err(dev, "Timeout waiting for %s memory repair\n",
0269 pd->base.name);
0270 ret = -ETIMEDOUT;
0271 goto err_disable_ispow;
0272 }
0273 }
0274
0275
0276 PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
0277
0278 return 0;
0279
0280 err_disable_ispow:
0281 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
0282 err_disable_powup:
0283 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
0284 return ret;
0285 }
0286
0287 static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
0288 u32 pm_reg,
0289 u32 asb_m_reg,
0290 u32 asb_s_reg,
0291 u32 reset_flags)
0292 {
0293 struct bcm2835_power *power = pd->power;
0294 int ret;
0295
0296 ret = clk_prepare_enable(pd->clk);
0297 if (ret) {
0298 dev_err(power->dev, "Failed to enable clock for %s\n",
0299 pd->base.name);
0300 return ret;
0301 }
0302
0303
0304 udelay(1);
0305
0306 clk_disable_unprepare(pd->clk);
0307
0308
0309 PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
0310
0311 ret = clk_prepare_enable(pd->clk);
0312 if (ret) {
0313 dev_err(power->dev, "Failed to enable clock for %s\n",
0314 pd->base.name);
0315 goto err_enable_resets;
0316 }
0317
0318 ret = bcm2835_asb_enable(power, asb_m_reg);
0319 if (ret) {
0320 dev_err(power->dev, "Failed to enable ASB master for %s\n",
0321 pd->base.name);
0322 goto err_disable_clk;
0323 }
0324 ret = bcm2835_asb_enable(power, asb_s_reg);
0325 if (ret) {
0326 dev_err(power->dev, "Failed to enable ASB slave for %s\n",
0327 pd->base.name);
0328 goto err_disable_asb_master;
0329 }
0330
0331 return 0;
0332
0333 err_disable_asb_master:
0334 bcm2835_asb_disable(power, asb_m_reg);
0335 err_disable_clk:
0336 clk_disable_unprepare(pd->clk);
0337 err_enable_resets:
0338 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
0339 return ret;
0340 }
0341
0342 static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
0343 u32 pm_reg,
0344 u32 asb_m_reg,
0345 u32 asb_s_reg,
0346 u32 reset_flags)
0347 {
0348 struct bcm2835_power *power = pd->power;
0349 int ret;
0350
0351 ret = bcm2835_asb_disable(power, asb_s_reg);
0352 if (ret) {
0353 dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
0354 pd->base.name);
0355 return ret;
0356 }
0357 ret = bcm2835_asb_disable(power, asb_m_reg);
0358 if (ret) {
0359 dev_warn(power->dev, "Failed to disable ASB master for %s\n",
0360 pd->base.name);
0361 bcm2835_asb_enable(power, asb_s_reg);
0362 return ret;
0363 }
0364
0365 clk_disable_unprepare(pd->clk);
0366
0367
0368 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
0369
0370 return 0;
0371 }
0372
0373 static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
0374 {
0375 struct bcm2835_power_domain *pd =
0376 container_of(domain, struct bcm2835_power_domain, base);
0377 struct bcm2835_power *power = pd->power;
0378
0379 switch (pd->domain) {
0380 case BCM2835_POWER_DOMAIN_GRAFX:
0381 return bcm2835_power_power_on(pd, PM_GRAFX);
0382
0383 case BCM2835_POWER_DOMAIN_GRAFX_V3D:
0384 return bcm2835_asb_power_on(pd, PM_GRAFX,
0385 ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
0386 PM_V3DRSTN);
0387
0388 case BCM2835_POWER_DOMAIN_IMAGE:
0389 return bcm2835_power_power_on(pd, PM_IMAGE);
0390
0391 case BCM2835_POWER_DOMAIN_IMAGE_PERI:
0392 return bcm2835_asb_power_on(pd, PM_IMAGE,
0393 0, 0,
0394 PM_PERIRSTN);
0395
0396 case BCM2835_POWER_DOMAIN_IMAGE_ISP:
0397 return bcm2835_asb_power_on(pd, PM_IMAGE,
0398 ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
0399 PM_ISPRSTN);
0400
0401 case BCM2835_POWER_DOMAIN_IMAGE_H264:
0402 return bcm2835_asb_power_on(pd, PM_IMAGE,
0403 ASB_H264_M_CTRL, ASB_H264_S_CTRL,
0404 PM_H264RSTN);
0405
0406 case BCM2835_POWER_DOMAIN_USB:
0407 PM_WRITE(PM_USB, PM_USB_CTRLEN);
0408 return 0;
0409
0410 case BCM2835_POWER_DOMAIN_DSI0:
0411 PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
0412 PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
0413 return 0;
0414
0415 case BCM2835_POWER_DOMAIN_DSI1:
0416 PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
0417 PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
0418 return 0;
0419
0420 case BCM2835_POWER_DOMAIN_CCP2TX:
0421 PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
0422 PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
0423 return 0;
0424
0425 case BCM2835_POWER_DOMAIN_HDMI:
0426 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
0427 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
0428 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
0429 usleep_range(100, 200);
0430 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
0431 return 0;
0432
0433 default:
0434 dev_err(power->dev, "Invalid domain %d\n", pd->domain);
0435 return -EINVAL;
0436 }
0437 }
0438
0439 static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
0440 {
0441 struct bcm2835_power_domain *pd =
0442 container_of(domain, struct bcm2835_power_domain, base);
0443 struct bcm2835_power *power = pd->power;
0444
0445 switch (pd->domain) {
0446 case BCM2835_POWER_DOMAIN_GRAFX:
0447 return bcm2835_power_power_off(pd, PM_GRAFX);
0448
0449 case BCM2835_POWER_DOMAIN_GRAFX_V3D:
0450 return bcm2835_asb_power_off(pd, PM_GRAFX,
0451 ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
0452 PM_V3DRSTN);
0453
0454 case BCM2835_POWER_DOMAIN_IMAGE:
0455 return bcm2835_power_power_off(pd, PM_IMAGE);
0456
0457 case BCM2835_POWER_DOMAIN_IMAGE_PERI:
0458 return bcm2835_asb_power_off(pd, PM_IMAGE,
0459 0, 0,
0460 PM_PERIRSTN);
0461
0462 case BCM2835_POWER_DOMAIN_IMAGE_ISP:
0463 return bcm2835_asb_power_off(pd, PM_IMAGE,
0464 ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
0465 PM_ISPRSTN);
0466
0467 case BCM2835_POWER_DOMAIN_IMAGE_H264:
0468 return bcm2835_asb_power_off(pd, PM_IMAGE,
0469 ASB_H264_M_CTRL, ASB_H264_S_CTRL,
0470 PM_H264RSTN);
0471
0472 case BCM2835_POWER_DOMAIN_USB:
0473 PM_WRITE(PM_USB, 0);
0474 return 0;
0475
0476 case BCM2835_POWER_DOMAIN_DSI0:
0477 PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
0478 PM_WRITE(PM_DSI0, 0);
0479 return 0;
0480
0481 case BCM2835_POWER_DOMAIN_DSI1:
0482 PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
0483 PM_WRITE(PM_DSI1, 0);
0484 return 0;
0485
0486 case BCM2835_POWER_DOMAIN_CCP2TX:
0487 PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
0488 PM_WRITE(PM_CCP2TX, 0);
0489 return 0;
0490
0491 case BCM2835_POWER_DOMAIN_HDMI:
0492 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
0493 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
0494 return 0;
0495
0496 default:
0497 dev_err(power->dev, "Invalid domain %d\n", pd->domain);
0498 return -EINVAL;
0499 }
0500 }
0501
0502 static int
0503 bcm2835_init_power_domain(struct bcm2835_power *power,
0504 int pd_xlate_index, const char *name)
0505 {
0506 struct device *dev = power->dev;
0507 struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
0508
0509 dom->clk = devm_clk_get(dev->parent, name);
0510 if (IS_ERR(dom->clk)) {
0511 int ret = PTR_ERR(dom->clk);
0512
0513 if (ret == -EPROBE_DEFER)
0514 return ret;
0515
0516
0517
0518
0519 dom->clk = NULL;
0520 }
0521
0522 dom->base.name = name;
0523 dom->base.power_on = bcm2835_power_pd_power_on;
0524 dom->base.power_off = bcm2835_power_pd_power_off;
0525
0526 dom->domain = pd_xlate_index;
0527 dom->power = power;
0528
0529
0530 pm_genpd_init(&dom->base, NULL, true);
0531
0532 power->pd_xlate.domains[pd_xlate_index] = &dom->base;
0533
0534 return 0;
0535 }
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545 static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
0546 unsigned long id)
0547 {
0548 struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
0549 reset);
0550 struct bcm2835_power_domain *pd;
0551 int ret;
0552
0553 switch (id) {
0554 case BCM2835_RESET_V3D:
0555 pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
0556 break;
0557 case BCM2835_RESET_H264:
0558 pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
0559 break;
0560 case BCM2835_RESET_ISP:
0561 pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
0562 break;
0563 default:
0564 dev_err(power->dev, "Bad reset id %ld\n", id);
0565 return -EINVAL;
0566 }
0567
0568 ret = bcm2835_power_pd_power_off(&pd->base);
0569 if (ret)
0570 return ret;
0571
0572 return bcm2835_power_pd_power_on(&pd->base);
0573 }
0574
0575 static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
0576 unsigned long id)
0577 {
0578 struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
0579 reset);
0580
0581 switch (id) {
0582 case BCM2835_RESET_V3D:
0583 return !PM_READ(PM_GRAFX & PM_V3DRSTN);
0584 case BCM2835_RESET_H264:
0585 return !PM_READ(PM_IMAGE & PM_H264RSTN);
0586 case BCM2835_RESET_ISP:
0587 return !PM_READ(PM_IMAGE & PM_ISPRSTN);
0588 default:
0589 return -EINVAL;
0590 }
0591 }
0592
0593 static const struct reset_control_ops bcm2835_reset_ops = {
0594 .reset = bcm2835_reset_reset,
0595 .status = bcm2835_reset_status,
0596 };
0597
0598 static const char *const power_domain_names[] = {
0599 [BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
0600 [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
0601
0602 [BCM2835_POWER_DOMAIN_IMAGE] = "image",
0603 [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
0604 [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
0605 [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
0606
0607 [BCM2835_POWER_DOMAIN_USB] = "usb",
0608 [BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
0609 [BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
0610 [BCM2835_POWER_DOMAIN_CAM0] = "cam0",
0611 [BCM2835_POWER_DOMAIN_CAM1] = "cam1",
0612 [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
0613 [BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
0614 };
0615
0616 static int bcm2835_power_probe(struct platform_device *pdev)
0617 {
0618 struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
0619 struct device *dev = &pdev->dev;
0620 struct bcm2835_power *power;
0621 static const struct {
0622 int parent, child;
0623 } domain_deps[] = {
0624 { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
0625 { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
0626 { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
0627 { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
0628 { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
0629 { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
0630 { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
0631 };
0632 int ret = 0, i;
0633 u32 id;
0634
0635 power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
0636 if (!power)
0637 return -ENOMEM;
0638 platform_set_drvdata(pdev, power);
0639
0640 power->dev = dev;
0641 power->base = pm->base;
0642 power->asb = pm->asb;
0643 power->rpivid_asb = pm->rpivid_asb;
0644
0645 id = readl(power->asb + ASB_AXI_BRDG_ID);
0646 if (id != BCM2835_BRDG_ID ) {
0647 dev_err(dev, "ASB register ID returned 0x%08x\n", id);
0648 return -ENODEV;
0649 }
0650
0651 if (power->rpivid_asb) {
0652 id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
0653 if (id != BCM2835_BRDG_ID ) {
0654 dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
0655 id);
0656 return -ENODEV;
0657 }
0658 }
0659
0660 power->pd_xlate.domains = devm_kcalloc(dev,
0661 ARRAY_SIZE(power_domain_names),
0662 sizeof(*power->pd_xlate.domains),
0663 GFP_KERNEL);
0664 if (!power->pd_xlate.domains)
0665 return -ENOMEM;
0666
0667 power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
0668
0669 for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
0670 ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
0671 if (ret)
0672 goto fail;
0673 }
0674
0675 for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
0676 pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
0677 &power->domains[domain_deps[i].child].base);
0678 }
0679
0680 power->reset.owner = THIS_MODULE;
0681 power->reset.nr_resets = BCM2835_RESET_COUNT;
0682 power->reset.ops = &bcm2835_reset_ops;
0683 power->reset.of_node = dev->parent->of_node;
0684
0685 ret = devm_reset_controller_register(dev, &power->reset);
0686 if (ret)
0687 goto fail;
0688
0689 of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
0690
0691 dev_info(dev, "Broadcom BCM2835 power domains driver");
0692 return 0;
0693
0694 fail:
0695 for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
0696 struct generic_pm_domain *dom = &power->domains[i].base;
0697
0698 if (dom->name)
0699 pm_genpd_remove(dom);
0700 }
0701 return ret;
0702 }
0703
0704 static int bcm2835_power_remove(struct platform_device *pdev)
0705 {
0706 return 0;
0707 }
0708
0709 static struct platform_driver bcm2835_power_driver = {
0710 .probe = bcm2835_power_probe,
0711 .remove = bcm2835_power_remove,
0712 .driver = {
0713 .name = "bcm2835-power",
0714 },
0715 };
0716 module_platform_driver(bcm2835_power_driver);
0717
0718 MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
0719 MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
0720 MODULE_LICENSE("GPL");