^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Power domain driver for Broadcom BCM2835
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2018 Broadcom
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <dt-bindings/soc/bcm2835-pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/mfd/bcm2835-pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/pm_domain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/reset-controller.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define PM_GNRIC 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define PM_AUDIO 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define PM_STATUS 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define PM_RSTC 0x1c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define PM_RSTS 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define PM_WDOG 0x24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define PM_PADS0 0x28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define PM_PADS2 0x2c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define PM_PADS3 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define PM_PADS4 0x34
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define PM_PADS5 0x38
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define PM_PADS6 0x3c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define PM_CAM0 0x44
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define PM_CAM0_LDOHPEN BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define PM_CAM0_LDOLPEN BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define PM_CAM0_CTRLEN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define PM_CAM1 0x48
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define PM_CAM1_LDOHPEN BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define PM_CAM1_LDOLPEN BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define PM_CAM1_CTRLEN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define PM_CCP2TX 0x4c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define PM_CCP2TX_LDOEN BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define PM_CCP2TX_CTRLEN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define PM_DSI0 0x50
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define PM_DSI0_LDOHPEN BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define PM_DSI0_LDOLPEN BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define PM_DSI0_CTRLEN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define PM_DSI1 0x54
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define PM_DSI1_LDOHPEN BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define PM_DSI1_LDOLPEN BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define PM_DSI1_CTRLEN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define PM_HDMI 0x58
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define PM_HDMI_RSTDR BIT(19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define PM_HDMI_LDOPD BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define PM_HDMI_CTRLEN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define PM_USB 0x5c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* The power gates must be enabled with this bit before enabling the LDO in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * USB block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define PM_USB_CTRLEN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define PM_PXLDO 0x60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define PM_PXBG 0x64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define PM_DFT 0x68
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define PM_SMPS 0x6c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define PM_XOSC 0x70
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define PM_SPAREW 0x74
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define PM_SPARER 0x78
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define PM_AVS_RSTDR 0x7c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define PM_AVS_STAT 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define PM_AVS_EVENT 0x84
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define PM_AVS_INTEN 0x88
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define PM_DUMMY 0xfc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define PM_IMAGE 0x108
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define PM_GRAFX 0x10c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define PM_PROC 0x110
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define PM_ENAB BIT(12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define PM_ISPRSTN BIT(8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define PM_H264RSTN BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define PM_PERIRSTN BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define PM_V3DRSTN BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define PM_ISFUNC BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define PM_MRDONE BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define PM_MEMREP BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define PM_ISPOW BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define PM_POWOK BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define PM_POWUP BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define PM_INRUSH_SHIFT 13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define PM_INRUSH_3_5_MA 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define PM_INRUSH_5_MA 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define PM_INRUSH_10_MA 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define PM_INRUSH_20_MA 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define PM_PASSWORD 0x5a000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define PM_WDOG_TIME_SET 0x000fffff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #define PM_RSTC_WRCFG_CLR 0xffffffcf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define PM_RSTS_HADWRH_SET 0x00000040
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define PM_RSTC_WRCFG_SET 0x00000030
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define PM_RSTC_WRCFG_FULL_RESET 0x00000020
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define PM_RSTC_RESET 0x00000102
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define PM_READ(reg) readl(power->base + (reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define ASB_BRDG_VERSION 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define ASB_CPR_CTRL 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define ASB_V3D_S_CTRL 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define ASB_V3D_M_CTRL 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define ASB_ISP_S_CTRL 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define ASB_ISP_M_CTRL 0x14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define ASB_H264_S_CTRL 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define ASB_H264_M_CTRL 0x1c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define ASB_REQ_STOP BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define ASB_ACK BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define ASB_EMPTY BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #define ASB_FULL BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #define ASB_AXI_BRDG_ID 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define ASB_READ(reg) readl(power->asb + (reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct bcm2835_power_domain {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct generic_pm_domain base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct bcm2835_power *power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) u32 domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct bcm2835_power {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* PM registers. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* AXI Async bridge registers. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) void __iomem *asb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct genpd_onecell_data pd_xlate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct reset_controller_dev reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) u64 start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (!reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) start = ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* Enable the module's async AXI bridges. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) while (ASB_READ(reg) & ASB_ACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (ktime_get_ns() - start >= 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) u64 start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (!reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) start = ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /* Enable the module's async AXI bridges. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) while (!(ASB_READ(reg) & ASB_ACK)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (ktime_get_ns() - start >= 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct bcm2835_power *power = pd->power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /* Enable functional isolation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* Enable electrical isolation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* Open the power switches. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) struct bcm2835_power *power = pd->power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct device *dev = power->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) u64 start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) int inrush;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) bool powok;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* If it was already powered on by the fw, leave it that way. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (PM_READ(pm_reg) & PM_POWUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* Enable power. Allowing too much current at once may result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * in POWOK never getting set, so start low and ramp it up as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * necessary to succeed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) powok = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) PM_WRITE(pm_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) (inrush << PM_INRUSH_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) PM_POWUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) start = ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (ktime_get_ns() - start >= 3000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (!powok) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) dev_err(dev, "Timeout waiting for %s power OK\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) pd->base.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) ret = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) goto err_disable_powup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /* Disable electrical isolation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /* Repair memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) start = ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) while (!(PM_READ(pm_reg) & PM_MRDONE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (ktime_get_ns() - start >= 1000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) dev_err(dev, "Timeout waiting for %s memory repair\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) pd->base.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) ret = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) goto err_disable_ispow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* Disable functional isolation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) err_disable_ispow:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) err_disable_powup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) u32 pm_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) u32 asb_m_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) u32 asb_s_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) u32 reset_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) struct bcm2835_power *power = pd->power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) ret = clk_prepare_enable(pd->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) dev_err(power->dev, "Failed to enable clock for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) pd->base.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* Wait 32 clocks for reset to propagate, 1 us will be enough */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) clk_disable_unprepare(pd->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /* Deassert the resets. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) ret = clk_prepare_enable(pd->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) dev_err(power->dev, "Failed to enable clock for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) pd->base.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) goto err_enable_resets;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) ret = bcm2835_asb_enable(power, asb_m_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) dev_err(power->dev, "Failed to enable ASB master for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) pd->base.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) goto err_disable_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) ret = bcm2835_asb_enable(power, asb_s_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) dev_err(power->dev, "Failed to enable ASB slave for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) pd->base.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) goto err_disable_asb_master;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) err_disable_asb_master:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) bcm2835_asb_disable(power, asb_m_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) err_disable_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) clk_disable_unprepare(pd->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) err_enable_resets:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) u32 pm_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) u32 asb_m_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) u32 asb_s_reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) u32 reset_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) struct bcm2835_power *power = pd->power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ret = bcm2835_asb_disable(power, asb_s_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) pd->base.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) ret = bcm2835_asb_disable(power, asb_m_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) dev_warn(power->dev, "Failed to disable ASB master for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) pd->base.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) bcm2835_asb_enable(power, asb_s_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) clk_disable_unprepare(pd->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /* Assert the resets. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) struct bcm2835_power_domain *pd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) container_of(domain, struct bcm2835_power_domain, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) struct bcm2835_power *power = pd->power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) switch (pd->domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) case BCM2835_POWER_DOMAIN_GRAFX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return bcm2835_power_power_on(pd, PM_GRAFX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) case BCM2835_POWER_DOMAIN_GRAFX_V3D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return bcm2835_asb_power_on(pd, PM_GRAFX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) PM_V3DRSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) case BCM2835_POWER_DOMAIN_IMAGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return bcm2835_power_power_on(pd, PM_IMAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) case BCM2835_POWER_DOMAIN_IMAGE_PERI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return bcm2835_asb_power_on(pd, PM_IMAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) PM_PERIRSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) case BCM2835_POWER_DOMAIN_IMAGE_ISP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return bcm2835_asb_power_on(pd, PM_IMAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) PM_ISPRSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) case BCM2835_POWER_DOMAIN_IMAGE_H264:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return bcm2835_asb_power_on(pd, PM_IMAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) ASB_H264_M_CTRL, ASB_H264_S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) PM_H264RSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) case BCM2835_POWER_DOMAIN_USB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) PM_WRITE(PM_USB, PM_USB_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) case BCM2835_POWER_DOMAIN_DSI0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) case BCM2835_POWER_DOMAIN_DSI1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) case BCM2835_POWER_DOMAIN_CCP2TX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) case BCM2835_POWER_DOMAIN_HDMI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) usleep_range(100, 200);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) dev_err(power->dev, "Invalid domain %d\n", pd->domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) struct bcm2835_power_domain *pd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) container_of(domain, struct bcm2835_power_domain, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) struct bcm2835_power *power = pd->power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) switch (pd->domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) case BCM2835_POWER_DOMAIN_GRAFX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return bcm2835_power_power_off(pd, PM_GRAFX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) case BCM2835_POWER_DOMAIN_GRAFX_V3D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return bcm2835_asb_power_off(pd, PM_GRAFX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) PM_V3DRSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) case BCM2835_POWER_DOMAIN_IMAGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return bcm2835_power_power_off(pd, PM_IMAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) case BCM2835_POWER_DOMAIN_IMAGE_PERI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) return bcm2835_asb_power_off(pd, PM_IMAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) PM_PERIRSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) case BCM2835_POWER_DOMAIN_IMAGE_ISP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return bcm2835_asb_power_off(pd, PM_IMAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) PM_ISPRSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) case BCM2835_POWER_DOMAIN_IMAGE_H264:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return bcm2835_asb_power_off(pd, PM_IMAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) ASB_H264_M_CTRL, ASB_H264_S_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) PM_H264RSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) case BCM2835_POWER_DOMAIN_USB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) PM_WRITE(PM_USB, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) case BCM2835_POWER_DOMAIN_DSI0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) PM_WRITE(PM_DSI0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) case BCM2835_POWER_DOMAIN_DSI1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) PM_WRITE(PM_DSI1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) case BCM2835_POWER_DOMAIN_CCP2TX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) PM_WRITE(PM_CCP2TX, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) case BCM2835_POWER_DOMAIN_HDMI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) dev_err(power->dev, "Invalid domain %d\n", pd->domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) bcm2835_init_power_domain(struct bcm2835_power *power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) int pd_xlate_index, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) struct device *dev = power->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) dom->clk = devm_clk_get(dev->parent, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (IS_ERR(dom->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) int ret = PTR_ERR(dom->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (ret == -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) /* Some domains don't have a clk, so make sure that we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * don't deref an error pointer later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) dom->clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) dom->base.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) dom->base.power_on = bcm2835_power_pd_power_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dom->base.power_off = bcm2835_power_pd_power_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) dom->domain = pd_xlate_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) dom->power = power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) /* XXX: on/off at boot? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) pm_genpd_init(&dom->base, NULL, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) power->pd_xlate.domains[pd_xlate_index] = &dom->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) /** bcm2835_reset_reset - Resets a block that has a reset line in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * PM block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * The consumer of the reset controller must have the power domain up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * -- there's no reset ability with the power domain down. To reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * the sub-block, we just disable its access to memory through the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * ASB, reset, and re-enable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) unsigned long id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) struct bcm2835_power_domain *pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) switch (id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) case BCM2835_RESET_V3D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) case BCM2835_RESET_H264:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) case BCM2835_RESET_ISP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) dev_err(power->dev, "Bad reset id %ld\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) ret = bcm2835_power_pd_power_off(&pd->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) return bcm2835_power_pd_power_on(&pd->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) unsigned long id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) switch (id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) case BCM2835_RESET_V3D:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) return !PM_READ(PM_GRAFX & PM_V3DRSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) case BCM2835_RESET_H264:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return !PM_READ(PM_IMAGE & PM_H264RSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) case BCM2835_RESET_ISP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) return !PM_READ(PM_IMAGE & PM_ISPRSTN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) static const struct reset_control_ops bcm2835_reset_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) .reset = bcm2835_reset_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) .status = bcm2835_reset_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) static const char *const power_domain_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) [BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) [BCM2835_POWER_DOMAIN_IMAGE] = "image",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) [BCM2835_POWER_DOMAIN_USB] = "usb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) [BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) [BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) [BCM2835_POWER_DOMAIN_CAM0] = "cam0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) [BCM2835_POWER_DOMAIN_CAM1] = "cam1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) [BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) static int bcm2835_power_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) struct bcm2835_power *power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) int parent, child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) } domain_deps[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) int ret = 0, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) u32 id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (!power)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) platform_set_drvdata(pdev, power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) power->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) power->base = pm->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) power->asb = pm->asb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) id = ASB_READ(ASB_AXI_BRDG_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) if (id != 0x62726467 /* "BRDG" */) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) dev_err(dev, "ASB register ID returned 0x%08x\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) power->pd_xlate.domains = devm_kcalloc(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) ARRAY_SIZE(power_domain_names),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) sizeof(*power->pd_xlate.domains),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if (!power->pd_xlate.domains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) &power->domains[domain_deps[i].child].base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) power->reset.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) power->reset.nr_resets = BCM2835_RESET_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) power->reset.ops = &bcm2835_reset_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) power->reset.of_node = dev->parent->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) ret = devm_reset_controller_register(dev, &power->reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) dev_info(dev, "Broadcom BCM2835 power domains driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) struct generic_pm_domain *dom = &power->domains[i].base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) if (dom->name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) pm_genpd_remove(dom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) static int bcm2835_power_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) static struct platform_driver bcm2835_power_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) .probe = bcm2835_power_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) .remove = bcm2835_power_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) .name = "bcm2835-power",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) module_platform_driver(bcm2835_power_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) MODULE_LICENSE("GPL");