xref: /openbsd-src/sys/dev/fdt/imxsrc.c (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
1 /* $OpenBSD: imxsrc.c,v 1.1 2019/01/11 08:02:19 patrick 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/cpufunc.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 IMX8M_RESET_PCIEPHY			20
31 #define IMX8M_RESET_PCIEPHY_PERST		21
32 #define IMX8M_RESET_PCIE_CTRL_APPS_EN		22
33 #define IMX8M_RESET_PCIE_CTRL_APPS_TURNOFF	25
34 #define IMX8M_RESET_PCIE_CTRL_APPS_CLK_REQ	26
35 #define IMX8M_RESET_PCIE2PHY			33
36 #define IMX8M_RESET_PCIE2PHY_PERST		34
37 #define IMX8M_RESET_PCIE2_CTRL_APPS_EN		35
38 #define IMX8M_RESET_PCIE2_CTRL_APPS_CLK_REQ	36
39 #define IMX8M_RESET_PCIE2_CTRL_APPS_TURNOFF	37
40 
41 #define SRC_PCIE1_RCR				0x2c
42 #define SRC_PCIE2_RCR				0x48
43 #define  SRC_PCIE_RCR_PCIEPHY_G_RST			(1 << 1)
44 #define  SRC_PCIE_RCR_PCIEPHY_BTN			(1 << 2)
45 #define  SRC_PCIE_RCR_PCIEPHY_PERST			(1 << 3)
46 #define  SRC_PCIE_RCR_PCIE_CTRL_APPS_CLK_REQ		(1 << 4)
47 #define  SRC_PCIE_RCR_PCIE_CTRL_APPS_EN			(1 << 6)
48 #define  SRC_PCIE_RCR_PCIE_CTRL_APPS_TURNOFF		(1 << 11)
49 
50 struct imxsrc_reset {
51 	uint32_t	reg;
52 	uint32_t	bit;
53 };
54 
55 struct imxsrc_reset imx8m_resets[] = {
56 	[IMX8M_RESET_PCIEPHY] = { SRC_PCIE1_RCR, SRC_PCIE_RCR_PCIEPHY_G_RST | SRC_PCIE_RCR_PCIEPHY_BTN },
57 	[IMX8M_RESET_PCIEPHY_PERST] = { SRC_PCIE1_RCR, SRC_PCIE_RCR_PCIEPHY_PERST },
58 	[IMX8M_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIE1_RCR, SRC_PCIE_RCR_PCIE_CTRL_APPS_EN },
59 	[IMX8M_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIE1_RCR, SRC_PCIE_RCR_PCIE_CTRL_APPS_TURNOFF },
60 	[IMX8M_RESET_PCIE_CTRL_APPS_CLK_REQ] = { SRC_PCIE1_RCR, SRC_PCIE_RCR_PCIE_CTRL_APPS_CLK_REQ },
61 	[IMX8M_RESET_PCIE2PHY] = { SRC_PCIE2_RCR, SRC_PCIE_RCR_PCIEPHY_G_RST | SRC_PCIE_RCR_PCIEPHY_BTN },
62 	[IMX8M_RESET_PCIE2PHY_PERST] = { SRC_PCIE2_RCR, SRC_PCIE_RCR_PCIEPHY_PERST },
63 	[IMX8M_RESET_PCIE2_CTRL_APPS_EN] = { SRC_PCIE2_RCR, SRC_PCIE_RCR_PCIE_CTRL_APPS_EN },
64 	[IMX8M_RESET_PCIE2_CTRL_APPS_CLK_REQ] = { SRC_PCIE2_RCR, SRC_PCIE_RCR_PCIE_CTRL_APPS_CLK_REQ },
65 	[IMX8M_RESET_PCIE2_CTRL_APPS_TURNOFF] = { SRC_PCIE2_RCR, SRC_PCIE_RCR_PCIE_CTRL_APPS_TURNOFF },
66 };
67 
68 #define HREAD4(sc, reg)							\
69 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
70 #define HWRITE4(sc, reg, val)						\
71 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
72 #define HSET4(sc, reg, bits)						\
73 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
74 #define HCLR4(sc, reg, bits)						\
75 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
76 
77 struct imxsrc_softc {
78 	struct device		 sc_dev;
79 	bus_space_tag_t		 sc_iot;
80 	bus_space_handle_t	 sc_ioh;
81 	struct reset_device	 sc_rd;
82 	struct imxsrc_reset	*sc_resets;
83 	int			 sc_nresets;
84 };
85 
86 int imxsrc_match(struct device *, void *, void *);
87 void imxsrc_attach(struct device *, struct device *, void *);
88 void imxsrc_reset(void *, uint32_t *, int);
89 
90 struct cfattach	imxsrc_ca = {
91 	sizeof (struct imxsrc_softc), imxsrc_match, imxsrc_attach
92 };
93 
94 struct cfdriver imxsrc_cd = {
95 	NULL, "imxsrc", DV_DULL
96 };
97 
98 int
99 imxsrc_match(struct device *parent, void *match, void *aux)
100 {
101 	struct fdt_attach_args *faa = aux;
102 
103 	return OF_is_compatible(faa->fa_node, "fsl,imx8mq-src");
104 }
105 
106 void
107 imxsrc_attach(struct device *parent, struct device *self, void *aux)
108 {
109 	struct imxsrc_softc *sc = (struct imxsrc_softc *)self;
110 	struct fdt_attach_args *faa = aux;
111 
112 	KASSERT(faa->fa_nreg >= 1);
113 
114 	sc->sc_iot = faa->fa_iot;
115 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
116 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
117 		panic("%s: bus_space_map failed!", __func__);
118 
119 	sc->sc_resets = imx8m_resets;
120 	sc->sc_nresets = nitems(imx8m_resets);
121 
122 	sc->sc_rd.rd_node = faa->fa_node;
123 	sc->sc_rd.rd_cookie = sc;
124 	sc->sc_rd.rd_reset = imxsrc_reset;
125 	reset_register(&sc->sc_rd);
126 
127 	printf("\n");
128 }
129 
130 void
131 imxsrc_reset(void *cookie, uint32_t *cells, int assert)
132 {
133 	struct imxsrc_softc *sc = cookie;
134 	int idx = cells[0];
135 	uint32_t reg;
136 
137 	if (idx >= sc->sc_nresets || sc->sc_resets[idx].bit == 0) {
138 		printf("%s: 0x%08x\n", __func__, idx);
139 		return;
140 	}
141 
142 	switch (idx) {
143 	case IMX8M_RESET_PCIEPHY:
144 	case IMX8M_RESET_PCIE2PHY:
145 		if (!assert)
146 			delay(10);
147 		break;
148 	case IMX8M_RESET_PCIE_CTRL_APPS_EN:
149 	case IMX8M_RESET_PCIE2_CTRL_APPS_EN:
150 		assert = !assert;
151 		break;
152 	}
153 
154 	reg = HREAD4(sc, sc->sc_resets[idx].reg);
155 	if (assert)
156 		reg |= sc->sc_resets[idx].bit;
157 	else
158 		reg &= ~sc->sc_resets[idx].bit;
159 	HWRITE4(sc, sc->sc_resets[idx].reg, reg);
160 }
161