1 /* $OpenBSD: imxsrc.c,v 1.6 2022/06/28 23:43:12 naddy Exp $ */
2 /*
3 * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/types.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_clock.h>
28 #include <dev/ofw/fdt.h>
29
30 #define IMX51_RESET_GPU 0
31 #define IMX51_RESET_VPU 1
32 #define IMX51_RESET_IPU1 2
33 #define IMX51_RESET_OPEN_VG 3
34 #define IMX51_RESET_IPU2 4
35
36 #define SRC_SCR 0x00
37 #define SRC_SCR_SW_GPU_RST (1 << 1)
38 #define SRC_SCR_SW_VPU_RST (1 << 2)
39 #define SRC_SCR_SW_IPU1_RST (1 << 3)
40 #define SRC_SCR_SW_OPEN_VG_RST (1 << 4)
41 #define SRC_SCR_SW_IPU2_RST (1 << 12)
42
43 #define IMX8M_RESET_PCIEPHY 26
44 #define IMX8M_RESET_PCIEPHY_PERST 27
45 #define IMX8M_RESET_PCIE_CTRL_APPS_EN 28
46 #define IMX8M_RESET_PCIE_CTRL_APPS_TURNOFF 29
47 #define IMX8M_RESET_PCIE2PHY 34
48 #define IMX8M_RESET_PCIE2PHY_PERST 35
49 #define IMX8M_RESET_PCIE2_CTRL_APPS_EN 36
50 #define IMX8M_RESET_PCIE2_CTRL_APPS_TURNOFF 37
51
52 #define SRC_PCIE1_RCR 0x2c
53 #define SRC_PCIE2_RCR 0x48
54 #define SRC_PCIE_RCR_PCIEPHY_G_RST (1 << 1)
55 #define SRC_PCIE_RCR_PCIEPHY_BTN (1 << 2)
56 #define SRC_PCIE_RCR_PCIEPHY_PERST (1 << 3)
57 #define SRC_PCIE_RCR_PCIE_CTRL_APPS_EN (1 << 6)
58 #define SRC_PCIE_RCR_PCIE_CTRL_APPS_TURNOFF (1 << 11)
59
60 struct imxsrc_reset {
61 uint32_t reg;
62 uint32_t bit;
63 };
64
65 const struct imxsrc_reset imx51_resets[] = {
66 [IMX51_RESET_GPU] = { SRC_SCR, SRC_SCR_SW_GPU_RST },
67 [IMX51_RESET_VPU] = { SRC_SCR, SRC_SCR_SW_VPU_RST },
68 [IMX51_RESET_IPU1] = { SRC_SCR, SRC_SCR_SW_IPU1_RST },
69 [IMX51_RESET_OPEN_VG] = { SRC_SCR, SRC_SCR_SW_OPEN_VG_RST },
70 [IMX51_RESET_IPU2] = { SRC_SCR, SRC_SCR_SW_IPU2_RST },
71 };
72
73 const struct imxsrc_reset imx8m_resets[] = {
74 [IMX8M_RESET_PCIEPHY] = { SRC_PCIE1_RCR,
75 SRC_PCIE_RCR_PCIEPHY_G_RST | SRC_PCIE_RCR_PCIEPHY_BTN },
76 [IMX8M_RESET_PCIEPHY_PERST] = { SRC_PCIE1_RCR,
77 SRC_PCIE_RCR_PCIEPHY_PERST },
78 [IMX8M_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIE1_RCR,
79 SRC_PCIE_RCR_PCIE_CTRL_APPS_EN },
80 [IMX8M_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIE1_RCR,
81 SRC_PCIE_RCR_PCIE_CTRL_APPS_TURNOFF },
82 [IMX8M_RESET_PCIE2PHY] = { SRC_PCIE2_RCR,
83 SRC_PCIE_RCR_PCIEPHY_G_RST | SRC_PCIE_RCR_PCIEPHY_BTN },
84 [IMX8M_RESET_PCIE2PHY_PERST] = { SRC_PCIE2_RCR,
85 SRC_PCIE_RCR_PCIEPHY_PERST },
86 [IMX8M_RESET_PCIE2_CTRL_APPS_EN] = { SRC_PCIE2_RCR,
87 SRC_PCIE_RCR_PCIE_CTRL_APPS_EN },
88 [IMX8M_RESET_PCIE2_CTRL_APPS_TURNOFF] = { SRC_PCIE2_RCR,
89 SRC_PCIE_RCR_PCIE_CTRL_APPS_TURNOFF },
90 };
91
92 #define HREAD4(sc, reg) \
93 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
94 #define HWRITE4(sc, reg, val) \
95 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
96 #define HSET4(sc, reg, bits) \
97 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
98 #define HCLR4(sc, reg, bits) \
99 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
100
101 struct imxsrc_softc {
102 struct device sc_dev;
103 bus_space_tag_t sc_iot;
104 bus_space_handle_t sc_ioh;
105 struct reset_device sc_rd;
106 const struct imxsrc_reset *sc_resets;
107 int sc_nresets;
108 };
109
110 int imxsrc_match(struct device *, void *, void *);
111 void imxsrc_attach(struct device *, struct device *, void *);
112 void imxsrc_reset(void *, uint32_t *, int);
113
114 const struct cfattach imxsrc_ca = {
115 sizeof (struct imxsrc_softc), imxsrc_match, imxsrc_attach
116 };
117
118 struct cfdriver imxsrc_cd = {
119 NULL, "imxsrc", DV_DULL
120 };
121
122 int
imxsrc_match(struct device * parent,void * match,void * aux)123 imxsrc_match(struct device *parent, void *match, void *aux)
124 {
125 struct fdt_attach_args *faa = aux;
126
127 if (OF_is_compatible(faa->fa_node, "fsl,imx51-src") ||
128 OF_is_compatible(faa->fa_node, "fsl,imx8mq-src"))
129 return 10; /* Must beat syscon(4). */
130
131 return 0;
132 }
133
134 void
imxsrc_attach(struct device * parent,struct device * self,void * aux)135 imxsrc_attach(struct device *parent, struct device *self, void *aux)
136 {
137 struct imxsrc_softc *sc = (struct imxsrc_softc *)self;
138 struct fdt_attach_args *faa = aux;
139
140 KASSERT(faa->fa_nreg >= 1);
141
142 sc->sc_iot = faa->fa_iot;
143 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
144 faa->fa_reg[0].size, 0, &sc->sc_ioh))
145 panic("%s: bus_space_map failed!", __func__);
146
147 if (OF_is_compatible(faa->fa_node, "fsl,imx51-src")) {
148 sc->sc_resets = imx51_resets;
149 sc->sc_nresets = nitems(imx51_resets);
150 } else {
151 sc->sc_resets = imx8m_resets;
152 sc->sc_nresets = nitems(imx8m_resets);
153 }
154
155 sc->sc_rd.rd_node = faa->fa_node;
156 sc->sc_rd.rd_cookie = sc;
157 sc->sc_rd.rd_reset = imxsrc_reset;
158 reset_register(&sc->sc_rd);
159
160 printf("\n");
161 }
162
163 void
imxsrc_reset(void * cookie,uint32_t * cells,int assert)164 imxsrc_reset(void *cookie, uint32_t *cells, int assert)
165 {
166 struct imxsrc_softc *sc = cookie;
167 int idx = cells[0];
168 uint32_t reg;
169
170 if (idx >= sc->sc_nresets || sc->sc_resets[idx].bit == 0) {
171 printf("%s: 0x%08x\n", __func__, idx);
172 return;
173 }
174
175 switch (idx) {
176 case IMX8M_RESET_PCIEPHY:
177 case IMX8M_RESET_PCIE2PHY:
178 if (!assert)
179 delay(10);
180 break;
181 case IMX8M_RESET_PCIE_CTRL_APPS_EN:
182 case IMX8M_RESET_PCIE2_CTRL_APPS_EN:
183 assert = !assert;
184 break;
185 }
186
187 reg = HREAD4(sc, sc->sc_resets[idx].reg);
188 if (assert)
189 reg |= sc->sc_resets[idx].bit;
190 else
191 reg &= ~sc->sc_resets[idx].bit;
192 HWRITE4(sc, sc->sc_resets[idx].reg, reg);
193 }
194