Defer display hardware reset to pipeline activation. This way, if we have a pipeline setup which we can't manage, the simple framebuffer will keep working.diff -r1.8 -r1.9 src/sys/arch/arm/sunxi/sunxi_debe.c
(bouyer)
--- src/sys/arch/arm/sunxi/sunxi_debe.c 2018/04/07 18:09:33 1.8
+++ src/sys/arch/arm/sunxi/sunxi_debe.c 2018/06/01 17:18:44 1.9
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sunxi_debe.c,v 1.8 2018/04/07 18:09:33 bouyer Exp $ */ | 1 | /* $NetBSD: sunxi_debe.c,v 1.9 2018/06/01 17:18:44 bouyer Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2018 Manuel Bouyer <bouyer@antioche.eu.org> | 4 | * Copyright (c) 2018 Manuel Bouyer <bouyer@antioche.eu.org> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> | 7 | * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> | |
8 | * All rights reserved. | 8 | * All rights reserved. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -28,27 +28,27 @@ | @@ -28,27 +28,27 @@ | |||
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include "genfb.h" | 32 | #include "genfb.h" | |
33 | 33 | |||
34 | #ifndef SUNXI_DEBE_VIDEOMEM | 34 | #ifndef SUNXI_DEBE_VIDEOMEM | |
35 | #define SUNXI_DEBE_VIDEOMEM (16 * 1024 * 1024) | 35 | #define SUNXI_DEBE_VIDEOMEM (16 * 1024 * 1024) | |
36 | #endif | 36 | #endif | |
37 | 37 | |||
38 | #define SUNXI_DEBE_CURMAX 64 | 38 | #define SUNXI_DEBE_CURMAX 64 | |
39 | 39 | |||
40 | #include <sys/cdefs.h> | 40 | #include <sys/cdefs.h> | |
41 | __KERNEL_RCSID(0, "$NetBSD: sunxi_debe.c,v 1.8 2018/04/07 18:09:33 bouyer Exp $"); | 41 | __KERNEL_RCSID(0, "$NetBSD: sunxi_debe.c,v 1.9 2018/06/01 17:18:44 bouyer Exp $"); | |
42 | 42 | |||
43 | #include <sys/param.h> | 43 | #include <sys/param.h> | |
44 | #include <sys/bus.h> | 44 | #include <sys/bus.h> | |
45 | #include <sys/device.h> | 45 | #include <sys/device.h> | |
46 | #include <sys/intr.h> | 46 | #include <sys/intr.h> | |
47 | #include <sys/systm.h> | 47 | #include <sys/systm.h> | |
48 | #include <sys/kernel.h> | 48 | #include <sys/kernel.h> | |
49 | #include <sys/mutex.h> | 49 | #include <sys/mutex.h> | |
50 | #include <sys/condvar.h> | 50 | #include <sys/condvar.h> | |
51 | 51 | |||
52 | #include <dev/fdt/fdtvar.h> | 52 | #include <dev/fdt/fdtvar.h> | |
53 | #include <dev/fdt/fdt_port.h> | 53 | #include <dev/fdt/fdt_port.h> | |
54 | 54 | |||
@@ -67,26 +67,28 @@ enum sunxi_debe_type { | @@ -67,26 +67,28 @@ enum sunxi_debe_type { | |||
67 | 67 | |||
68 | struct sunxi_debe_softc { | 68 | struct sunxi_debe_softc { | |
69 | device_t sc_dev; | 69 | device_t sc_dev; | |
70 | device_t sc_fbdev; | 70 | device_t sc_fbdev; | |
71 | enum sunxi_debe_type sc_type; | 71 | enum sunxi_debe_type sc_type; | |
72 | bus_space_tag_t sc_bst; | 72 | bus_space_tag_t sc_bst; | |
73 | bus_space_handle_t sc_bsh; | 73 | bus_space_handle_t sc_bsh; | |
74 | bus_dma_tag_t sc_dmat; | 74 | bus_dma_tag_t sc_dmat; | |
75 | 75 | |||
76 | struct clk *sc_clk_ahb; | 76 | struct clk *sc_clk_ahb; | |
77 | struct clk *sc_clk_mod; | 77 | struct clk *sc_clk_mod; | |
78 | struct clk *sc_clk_ram; | 78 | struct clk *sc_clk_ram; | |
79 | 79 | |||
80 | struct fdtbus_reset *sc_rst; | |||
81 | ||||
80 | bus_dma_segment_t sc_dmasegs[1]; | 82 | bus_dma_segment_t sc_dmasegs[1]; | |
81 | bus_size_t sc_dmasize; | 83 | bus_size_t sc_dmasize; | |
82 | bus_dmamap_t sc_dmamap; | 84 | bus_dmamap_t sc_dmamap; | |
83 | void *sc_dmap; | 85 | void *sc_dmap; | |
84 | 86 | |||
85 | bool sc_cursor_enable; | 87 | bool sc_cursor_enable; | |
86 | int sc_cursor_x, sc_cursor_y; | 88 | int sc_cursor_x, sc_cursor_y; | |
87 | int sc_hot_x, sc_hot_y; | 89 | int sc_hot_x, sc_hot_y; | |
88 | uint8_t sc_cursor_bitmap[8 * SUNXI_DEBE_CURMAX]; | 90 | uint8_t sc_cursor_bitmap[8 * SUNXI_DEBE_CURMAX]; | |
89 | uint8_t sc_cursor_mask[8 * SUNXI_DEBE_CURMAX]; | 91 | uint8_t sc_cursor_mask[8 * SUNXI_DEBE_CURMAX]; | |
90 | 92 | |||
91 | int sc_phandle; | 93 | int sc_phandle; | |
92 | struct fdt_device_ports sc_ports; | 94 | struct fdt_device_ports sc_ports; | |
@@ -142,118 +144,135 @@ sunxi_debe_match(device_t parent, cfdata | @@ -142,118 +144,135 @@ sunxi_debe_match(device_t parent, cfdata | |||
142 | struct fdt_attach_args * const faa = aux; | 144 | struct fdt_attach_args * const faa = aux; | |
143 | 145 | |||
144 | return of_match_compat_data(faa->faa_phandle, compat_data); | 146 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
145 | } | 147 | } | |
146 | 148 | |||
147 | static void | 149 | static void | |
148 | sunxi_debe_attach(device_t parent, device_t self, void *aux) | 150 | sunxi_debe_attach(device_t parent, device_t self, void *aux) | |
149 | { | 151 | { | |
150 | struct sunxi_debe_softc *sc = device_private(self); | 152 | struct sunxi_debe_softc *sc = device_private(self); | |
151 | struct fdt_attach_args * const faa = aux; | 153 | struct fdt_attach_args * const faa = aux; | |
152 | const int phandle = faa->faa_phandle; | 154 | const int phandle = faa->faa_phandle; | |
153 | bus_addr_t addr; | 155 | bus_addr_t addr; | |
154 | bus_size_t size; | 156 | bus_size_t size; | |
155 | struct fdtbus_reset *rst; | |||
156 | int error; | 157 | int error; | |
157 | 158 | |||
158 | sc->sc_dev = self; | 159 | sc->sc_dev = self; | |
159 | sc->sc_phandle = phandle; | 160 | sc->sc_phandle = phandle; | |
160 | sc->sc_bst = faa->faa_bst; | 161 | sc->sc_bst = faa->faa_bst; | |
161 | sc->sc_dmat = faa->faa_dmat; | 162 | sc->sc_dmat = faa->faa_dmat; | |
162 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | 163 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | |
163 | aprint_error(": couldn't get registers\n"); | 164 | aprint_error(": couldn't get registers\n"); | |
164 | } | 165 | } | |
165 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | 166 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | |
166 | aprint_error(": couldn't map registers\n"); | 167 | aprint_error(": couldn't map registers\n"); | |
167 | return; | 168 | return; | |
168 | } | 169 | } | |
169 | 170 | |||
170 | sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb"); | 171 | sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb"); | |
171 | sc->sc_clk_mod = fdtbus_clock_get(phandle, "mod"); | 172 | sc->sc_clk_mod = fdtbus_clock_get(phandle, "mod"); | |
172 | sc->sc_clk_ram = fdtbus_clock_get(phandle, "ram"); | 173 | sc->sc_clk_ram = fdtbus_clock_get(phandle, "ram"); | |
173 | 174 | |||
174 | rst = fdtbus_reset_get_index(phandle, 0); | |||
175 | if (rst == NULL) { | |||
176 | aprint_error(": couldn't get reset\n"); | |||
177 | return; | |||
178 | } | |||
179 | if (fdtbus_reset_assert(rst) != 0) { | |||
180 | aprint_error(": couldn't assert reset\n"); | |||
181 | return; | |||
182 | } | |||
183 | delay(1); | |||
184 | if (fdtbus_reset_deassert(rst) != 0) { | |||
185 | aprint_error(": couldn't de-assert reset\n"); | |||
186 | return; | |||
187 | } | |||
188 | ||||
189 | if (sc->sc_clk_ahb == NULL || sc->sc_clk_mod == NULL | 175 | if (sc->sc_clk_ahb == NULL || sc->sc_clk_mod == NULL | |
190 | || sc->sc_clk_ram == NULL) { | 176 | || sc->sc_clk_ram == NULL) { | |
191 | aprint_error(": couldn't get clocks\n"); | 177 | aprint_error(": couldn't get clocks\n"); | |
192 | aprint_debug_dev(self, "clk ahb %s mod %s ram %s\n", | 178 | aprint_debug_dev(self, "clk ahb %s mod %s ram %s\n", | |
193 | sc->sc_clk_ahb == NULL ? "missing" : "present", | 179 | sc->sc_clk_ahb == NULL ? "missing" : "present", | |
194 | sc->sc_clk_mod == NULL ? "missing" : "present", | 180 | sc->sc_clk_mod == NULL ? "missing" : "present", | |
195 | sc->sc_clk_ram == NULL ? "missing" : "present"); | 181 | sc->sc_clk_ram == NULL ? "missing" : "present"); | |
196 | return; | 182 | return; | |
197 | } | 183 | } | |
198 | 184 | |||
199 | error = clk_set_rate(sc->sc_clk_mod, 300000000); | 185 | sc->sc_rst = fdtbus_reset_get_index(phandle, 0); | |
200 | if (error) { | 186 | if (sc->sc_rst == NULL) { | |
201 | aprint_error("couln't set mod clock rate (%d)\n", error); | 187 | aprint_error(": couldn't get reset\n"); | |
202 | return; | |||
203 | } | |||
204 | ||||
205 | if (clk_enable(sc->sc_clk_ahb) != 0 || | |||
206 | clk_enable(sc->sc_clk_mod) != 0) { | |||
207 | aprint_error(": couldn't enable clocks\n"); | |||
208 | return; | 188 | return; | |
209 | } | 189 | } | |
210 | if (clk_disable(sc->sc_clk_ram) != 0) { | |||
211 | aprint_error(": couldn't disable ram clock\n"); | |||
212 | } | |||
213 | 190 | |||
214 | sc->sc_type = of_search_compatible(faa->faa_phandle, compat_data)->data; | 191 | sc->sc_type = of_search_compatible(faa->faa_phandle, compat_data)->data; | |
215 | 192 | |||
216 | aprint_naive("\n"); | 193 | aprint_naive("\n"); | |
217 | aprint_normal(": Display Engine Backend (%s)\n", | 194 | aprint_normal(": Display Engine Backend (%s)\n", | |
218 | fdtbus_get_string(phandle, "name")); | 195 | fdtbus_get_string(phandle, "name")); | |
219 | 196 | |||
220 | 197 | |||
221 | for (unsigned int reg = 0x800; reg < 0x1000; reg += 4) { | |||
222 | DEBE_WRITE(sc, reg, 0); | |||
223 | } | |||
224 | ||||
225 | DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, SUNXI_DEBE_MODCTL_EN); | |||
226 | ||||
227 | sc->sc_dmasize = SUNXI_DEBE_VIDEOMEM; | 198 | sc->sc_dmasize = SUNXI_DEBE_VIDEOMEM; | |
228 | 199 | |||
229 | DEBE_WRITE(sc, SUNXI_DEBE_HWC_PALETTE_TABLE, 0); | |||
230 | ||||
231 | error = sunxi_debe_alloc_videomem(sc); | 200 | error = sunxi_debe_alloc_videomem(sc); | |
232 | if (error) { | 201 | if (error) { | |
233 | aprint_error_dev(sc->sc_dev, | 202 | aprint_error_dev(sc->sc_dev, | |
234 | "couldn't allocate video memory, error = %d\n", error); | 203 | "couldn't allocate video memory, error = %d\n", error); | |
235 | return; | 204 | return; | |
236 | } | 205 | } | |
237 | 206 | |||
238 | sc->sc_unit = -1; | 207 | sc->sc_unit = -1; | |
239 | sc->sc_ports.dp_ep_connect = sunxi_debe_ep_connect; | 208 | sc->sc_ports.dp_ep_connect = sunxi_debe_ep_connect; | |
240 | sc->sc_ports.dp_ep_enable = sunxi_debe_ep_enable; | 209 | sc->sc_ports.dp_ep_enable = sunxi_debe_ep_enable; | |
241 | fdt_ports_register(&sc->sc_ports, self, phandle, EP_OTHER); | 210 | fdt_ports_register(&sc->sc_ports, self, phandle, EP_OTHER); | |
211 | } | |||
242 | 212 | |||
243 | if (clk_disable(sc->sc_clk_ahb) != 0 || | 213 | static void | |
244 | clk_disable(sc->sc_clk_mod) != 0) { | 214 | sunxi_debe_doreset(void) | |
245 | aprint_error(": couldn't disable clocks\n"); | 215 | { | |
246 | return; | 216 | device_t dev; | |
217 | struct sunxi_debe_softc *sc; | |||
218 | int error; | |||
219 | ||||
220 | for (int i = 0;;i++) { | |||
221 | dev = device_find_by_driver_unit("sunxidebe", i); | |||
222 | if (dev == NULL) | |||
223 | return; | |||
224 | sc = device_private(dev); | |||
225 | ||||
226 | if (fdtbus_reset_assert(sc->sc_rst) != 0) { | |||
227 | aprint_error_dev(dev, ": couldn't assert reset\n"); | |||
228 | return; | |||
229 | } | |||
230 | delay(1); | |||
231 | if (fdtbus_reset_deassert(sc->sc_rst) != 0) { | |||
232 | aprint_error_dev(dev, ": couldn't de-assert reset\n"); | |||
233 | return; | |||
234 | } | |||
235 | ||||
236 | ||||
237 | error = clk_set_rate(sc->sc_clk_mod, 300000000); | |||
238 | if (error) { | |||
239 | aprint_error_dev(dev, | |||
240 | "couln't set mod clock rate (%d)\n", error); | |||
241 | return; | |||
242 | } | |||
243 | ||||
244 | if (clk_enable(sc->sc_clk_ahb) != 0 || | |||
245 | clk_enable(sc->sc_clk_mod) != 0) { | |||
246 | aprint_error_dev(dev, ": couldn't enable clocks\n"); | |||
247 | return; | |||
248 | } | |||
249 | if (clk_disable(sc->sc_clk_ram) != 0) { | |||
250 | aprint_error_dev(dev, ": couldn't disable ram clock\n"); | |||
251 | } | |||
252 | ||||
253 | for (unsigned int reg = 0x800; reg < 0x1000; reg += 4) { | |||
254 | DEBE_WRITE(sc, reg, 0); | |||
255 | } | |||
256 | ||||
257 | DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, SUNXI_DEBE_MODCTL_EN); | |||
258 | ||||
259 | DEBE_WRITE(sc, SUNXI_DEBE_HWC_PALETTE_TABLE, 0); | |||
260 | ||||
261 | if (clk_disable(sc->sc_clk_ahb) != 0 || | |||
262 | clk_disable(sc->sc_clk_mod) != 0) { | |||
263 | aprint_error_dev(sc->sc_dev, | |||
264 | ": couldn't disable clocks\n"); | |||
265 | } | |||
247 | } | 266 | } | |
248 | } | 267 | } | |
249 | 268 | |||
250 | static void | 269 | static void | |
251 | sunxi_debe_ep_connect(device_t self, struct fdt_endpoint *ep, bool connect) | 270 | sunxi_debe_ep_connect(device_t self, struct fdt_endpoint *ep, bool connect) | |
252 | { | 271 | { | |
253 | struct sunxi_debe_softc *sc = device_private(self); | 272 | struct sunxi_debe_softc *sc = device_private(self); | |
254 | struct fdt_endpoint *rep = fdt_endpoint_remote(ep); | 273 | struct fdt_endpoint *rep = fdt_endpoint_remote(ep); | |
255 | int rep_idx = fdt_endpoint_index(rep); | 274 | int rep_idx = fdt_endpoint_index(rep); | |
256 | 275 | |||
257 | KASSERT(device_is_a(self, "sunxidebe")); | 276 | KASSERT(device_is_a(self, "sunxidebe")); | |
258 | if (!connect) { | 277 | if (!connect) { | |
259 | aprint_error_dev(self, "endpoint disconnect not supported\n"); | 278 | aprint_error_dev(self, "endpoint disconnect not supported\n"); | |
@@ -831,38 +850,46 @@ sunxi_befb_set_videomode(device_t dev, u | @@ -831,38 +850,46 @@ sunxi_befb_set_videomode(device_t dev, u | |||
831 | if (sc->sc_gen.sc_width != width || sc->sc_gen.sc_height != height) { | 850 | if (sc->sc_gen.sc_width != width || sc->sc_gen.sc_height != height) { | |
832 | device_printf(sc->sc_gen.sc_dev, | 851 | device_printf(sc->sc_gen.sc_dev, | |
833 | "mode switching not yet supported\n"); | 852 | "mode switching not yet supported\n"); | |
834 | } | 853 | } | |
835 | } | 854 | } | |
836 | 855 | |||
837 | int | 856 | int | |
838 | sunxi_debe_pipeline(int phandle, bool active) | 857 | sunxi_debe_pipeline(int phandle, bool active) | |
839 | { | 858 | { | |
840 | device_t dev; | 859 | device_t dev; | |
841 | struct sunxi_debe_softc *sc; | 860 | struct sunxi_debe_softc *sc; | |
842 | struct fdt_endpoint *ep; | 861 | struct fdt_endpoint *ep; | |
843 | int i, error; | 862 | int i, error; | |
863 | static bool reset_done = false; | |||
844 | 864 | |||
845 | if (!active) | 865 | if (!active) | |
846 | return EOPNOTSUPP; | 866 | return EOPNOTSUPP; | |
847 | 867 | |||
848 | for (i = 0;;i++) { | 868 | for (i = 0;;i++) { | |
849 | dev = device_find_by_driver_unit("sunxidebe", i); | 869 | dev = device_find_by_driver_unit("sunxidebe", i); | |
850 | if (dev == NULL) | 870 | if (dev == NULL) | |
851 | return ENODEV; | 871 | return ENODEV; | |
852 | sc = device_private(dev); | 872 | sc = device_private(dev); | |
853 | if (sc->sc_phandle == phandle) | 873 | if (sc->sc_phandle == phandle) | |
854 | break; | 874 | break; | |
855 | } | 875 | } | |
876 | if (!reset_done) { | |||
877 | sunxi_debe_doreset(); | |||
878 | sunxi_tcon_doreset(); | |||
879 | sunxi_hdmi_doreset(); | |||
880 | reset_done = true; | |||
881 | } | |||
882 | ||||
856 | aprint_normal("activate %s\n", device_xname(dev)); | 883 | aprint_normal("activate %s\n", device_xname(dev)); | |
857 | if (clk_enable(sc->sc_clk_ahb) != 0 || | 884 | if (clk_enable(sc->sc_clk_ahb) != 0 || | |
858 | clk_enable(sc->sc_clk_mod) != 0) { | 885 | clk_enable(sc->sc_clk_mod) != 0) { | |
859 | aprint_error_dev(dev, "couldn't enable clocks\n"); | 886 | aprint_error_dev(dev, "couldn't enable clocks\n"); | |
860 | return EIO; | 887 | return EIO; | |
861 | } | 888 | } | |
862 | /* connect debd0 to tcon0, debe1 to tcon1 */ | 889 | /* connect debd0 to tcon0, debe1 to tcon1 */ | |
863 | ep = fdt_endpoint_get_from_index(&sc->sc_ports, SUNXI_PORT_OUTPUT, | 890 | ep = fdt_endpoint_get_from_index(&sc->sc_ports, SUNXI_PORT_OUTPUT, | |
864 | sc->sc_unit); | 891 | sc->sc_unit); | |
865 | if (ep == NULL) { | 892 | if (ep == NULL) { | |
866 | aprint_error_dev(dev, "no output endpoint for %d\n", | 893 | aprint_error_dev(dev, "no output endpoint for %d\n", | |
867 | sc->sc_unit); | 894 | sc->sc_unit); | |
868 | return ENODEV; | 895 | return ENODEV; |
--- src/sys/arch/arm/sunxi/sunxi_display.h 2018/04/07 18:09:33 1.2
+++ src/sys/arch/arm/sunxi/sunxi_display.h 2018/06/01 17:18:44 1.3
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sunxi_display.h,v 1.2 2018/04/07 18:09:33 bouyer Exp $ */ | 1 | /* $NetBSD: sunxi_display.h,v 1.3 2018/06/01 17:18:44 bouyer Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2018 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2018 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Manuel Bouyer. | 8 | * by Manuel Bouyer. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -28,13 +28,16 @@ | @@ -28,13 +28,16 @@ | |||
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | 32 | |||
33 | #define SUNXI_PORT_INPUT 0 | 33 | #define SUNXI_PORT_INPUT 0 | |
34 | #define SUNXI_PORT_OUTPUT 1 | 34 | #define SUNXI_PORT_OUTPUT 1 | |
35 | 35 | |||
36 | struct videomode; | 36 | struct videomode; | |
37 | int sunxi_debe_pipeline(int, bool); | 37 | int sunxi_debe_pipeline(int, bool); | |
38 | void sunxi_tcon1_set_videomode(device_t, const struct videomode *); | 38 | void sunxi_tcon1_set_videomode(device_t, const struct videomode *); | |
39 | void sunxi_debe_set_videomode(device_t, const struct videomode *); | 39 | void sunxi_debe_set_videomode(device_t, const struct videomode *); | |
40 | bool sunxi_tcon_is_console(device_t, const char *); | 40 | bool sunxi_tcon_is_console(device_t, const char *); | |
41 | ||||
42 | void sunxi_tcon_doreset(void); | |||
43 | void sunxi_hdmi_doreset(void); |
--- src/sys/arch/arm/sunxi/sunxi_hdmi.c 2018/04/03 16:17:59 1.3
+++ src/sys/arch/arm/sunxi/sunxi_hdmi.c 2018/06/01 17:18:44 1.4
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sunxi_hdmi.c,v 1.3 2018/04/03 16:17:59 bouyer Exp $ */ | 1 | /* $NetBSD: sunxi_hdmi.c,v 1.4 2018/06/01 17:18:44 bouyer Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> | 4 | * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -19,27 +19,27 @@ | @@ -19,27 +19,27 @@ | |||
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include "opt_ddb.h" | 29 | #include "opt_ddb.h" | |
30 | 30 | |||
31 | #include <sys/cdefs.h> | 31 | #include <sys/cdefs.h> | |
32 | __KERNEL_RCSID(0, "$NetBSD: sunxi_hdmi.c,v 1.3 2018/04/03 16:17:59 bouyer Exp $"); | 32 | __KERNEL_RCSID(0, "$NetBSD: sunxi_hdmi.c,v 1.4 2018/06/01 17:18:44 bouyer Exp $"); | |
33 | 33 | |||
34 | #include <sys/param.h> | 34 | #include <sys/param.h> | |
35 | #include <sys/bus.h> | 35 | #include <sys/bus.h> | |
36 | #include <sys/device.h> | 36 | #include <sys/device.h> | |
37 | #include <sys/intr.h> | 37 | #include <sys/intr.h> | |
38 | #include <sys/systm.h> | 38 | #include <sys/systm.h> | |
39 | #include <sys/kernel.h> | 39 | #include <sys/kernel.h> | |
40 | #include <sys/proc.h> | 40 | #include <sys/proc.h> | |
41 | #include <sys/mutex.h> | 41 | #include <sys/mutex.h> | |
42 | #include <sys/kthread.h> | 42 | #include <sys/kthread.h> | |
43 | 43 | |||
44 | #include <dev/fdt/fdtvar.h> | 44 | #include <dev/fdt/fdtvar.h> | |
45 | #include <dev/fdt/fdt_port.h> | 45 | #include <dev/fdt/fdt_port.h> | |
@@ -155,27 +155,26 @@ sunxi_hdmi_match(device_t parent, cfdata | @@ -155,27 +155,26 @@ sunxi_hdmi_match(device_t parent, cfdata | |||
155 | 155 | |||
156 | return of_match_compat_data(faa->faa_phandle, compat_data); | 156 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
157 | } | 157 | } | |
158 | 158 | |||
159 | static void | 159 | static void | |
160 | sunxi_hdmi_attach(device_t parent, device_t self, void *aux) | 160 | sunxi_hdmi_attach(device_t parent, device_t self, void *aux) | |
161 | { | 161 | { | |
162 | struct sunxi_hdmi_softc *sc = device_private(self); | 162 | struct sunxi_hdmi_softc *sc = device_private(self); | |
163 | struct fdt_attach_args * const faa = aux; | 163 | struct fdt_attach_args * const faa = aux; | |
164 | const int phandle = faa->faa_phandle; | 164 | const int phandle = faa->faa_phandle; | |
165 | bus_addr_t addr; | 165 | bus_addr_t addr; | |
166 | bus_size_t size; | 166 | bus_size_t size; | |
167 | uint32_t ver; | 167 | uint32_t ver; | |
168 | int error; | |||
169 | 168 | |||
170 | sc->sc_dev = self; | 169 | sc->sc_dev = self; | |
171 | sc->sc_phandle = phandle; | 170 | sc->sc_phandle = phandle; | |
172 | sc->sc_bst = faa->faa_bst; | 171 | sc->sc_bst = faa->faa_bst; | |
173 | 172 | |||
174 | sc->sc_type = of_search_compatible(faa->faa_phandle, compat_data)->data; | 173 | sc->sc_type = of_search_compatible(faa->faa_phandle, compat_data)->data; | |
175 | 174 | |||
176 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | 175 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | |
177 | aprint_error(": couldn't get registers\n"); | 176 | aprint_error(": couldn't get registers\n"); | |
178 | } | 177 | } | |
179 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | 178 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | |
180 | aprint_error(": couldn't map registers\n"); | 179 | aprint_error(": couldn't map registers\n"); | |
181 | return; | 180 | return; | |
@@ -187,69 +186,84 @@ sunxi_hdmi_attach(device_t parent, devic | @@ -187,69 +186,84 @@ sunxi_hdmi_attach(device_t parent, devic | |||
187 | sc->sc_clk_pll1 = fdtbus_clock_get(phandle, "pll-1"); | 186 | sc->sc_clk_pll1 = fdtbus_clock_get(phandle, "pll-1"); | |
188 | 187 | |||
189 | if (sc->sc_clk_ahb == NULL || sc->sc_clk_mod == NULL | 188 | if (sc->sc_clk_ahb == NULL || sc->sc_clk_mod == NULL | |
190 | || sc->sc_clk_pll0 == NULL || sc->sc_clk_pll1 == NULL) { | 189 | || sc->sc_clk_pll0 == NULL || sc->sc_clk_pll1 == NULL) { | |
191 | aprint_error(": couldn't get clocks\n"); | 190 | aprint_error(": couldn't get clocks\n"); | |
192 | aprint_debug_dev(self, "clk ahb %s mod %s pll-0 %s pll-1 %s\n", | 191 | aprint_debug_dev(self, "clk ahb %s mod %s pll-0 %s pll-1 %s\n", | |
193 | sc->sc_clk_ahb == NULL ? "missing" : "present", | 192 | sc->sc_clk_ahb == NULL ? "missing" : "present", | |
194 | sc->sc_clk_mod == NULL ? "missing" : "present", | 193 | sc->sc_clk_mod == NULL ? "missing" : "present", | |
195 | sc->sc_clk_pll0 == NULL ? "missing" : "present", | 194 | sc->sc_clk_pll0 == NULL ? "missing" : "present", | |
196 | sc->sc_clk_pll1 == NULL ? "missing" : "present"); | 195 | sc->sc_clk_pll1 == NULL ? "missing" : "present"); | |
197 | return; | 196 | return; | |
198 | } | 197 | } | |
199 | 198 | |||
200 | error = clk_disable(sc->sc_clk_mod); | |||
201 | if (error) { | |||
202 | aprint_error(": couldn't disable mod clock\n"); | |||
203 | return; | |||
204 | } | |||
205 | ||||
206 | if (clk_enable(sc->sc_clk_ahb) != 0) { | 199 | if (clk_enable(sc->sc_clk_ahb) != 0) { | |
207 | aprint_error(": couldn't enable ahb clock\n"); | 200 | aprint_error(": couldn't enable ahb clock\n"); | |
208 | return; | 201 | return; | |
209 | } | 202 | } | |
210 | #if defined(SUNXI_HDMI_DEBUG) | |||
211 | sunxi_hdmi_dump_regs(); | |||
212 | #endif | |||
213 | ||||
214 | /* | |||
215 | * reset device, in case it has been setup by firmware in an | |||
216 | * incompatible way | |||
217 | */ | |||
218 | for (int i = 0; i <= 0x500; i += 4) { | |||
219 | HDMI_WRITE(sc, i, 0); | |||
220 | } | |||
221 | ||||
222 | ver = HDMI_READ(sc, SUNXI_HDMI_VERSION_ID_REG); | 203 | ver = HDMI_READ(sc, SUNXI_HDMI_VERSION_ID_REG); | |
223 | 204 | |||
224 | const int vmaj = __SHIFTOUT(ver, SUNXI_HDMI_VERSION_ID_H); | 205 | const int vmaj = __SHIFTOUT(ver, SUNXI_HDMI_VERSION_ID_H); | |
225 | const int vmin = __SHIFTOUT(ver, SUNXI_HDMI_VERSION_ID_L); | 206 | const int vmin = __SHIFTOUT(ver, SUNXI_HDMI_VERSION_ID_L); | |
226 | 207 | |||
227 | aprint_naive("\n"); | 208 | aprint_naive("\n"); | |
228 | aprint_normal(": HDMI %d.%d\n", vmaj, vmin); | 209 | aprint_normal(": HDMI %d.%d\n", vmaj, vmin); | |
229 | 210 | |||
230 | sc->sc_ver = ver; | 211 | sc->sc_ver = ver; | |
231 | sc->sc_i2c_blklen = 16; | 212 | sc->sc_i2c_blklen = 16; | |
232 | 213 | |||
233 | sc->sc_ports.dp_ep_activate = sunxi_hdmi_ep_activate; | 214 | sc->sc_ports.dp_ep_activate = sunxi_hdmi_ep_activate; | |
234 | sc->sc_ports.dp_ep_enable = sunxi_hdmi_ep_enable; | 215 | sc->sc_ports.dp_ep_enable = sunxi_hdmi_ep_enable; | |
235 | fdt_ports_register(&sc->sc_ports, self, phandle, EP_OTHER); | 216 | fdt_ports_register(&sc->sc_ports, self, phandle, EP_OTHER); | |
236 | 217 | |||
237 | mutex_init(&sc->sc_pwr_lock, MUTEX_DEFAULT, IPL_NONE); | 218 | mutex_init(&sc->sc_pwr_lock, MUTEX_DEFAULT, IPL_NONE); | |
238 | sunxi_hdmi_i2c_init(sc); | 219 | sunxi_hdmi_i2c_init(sc); | |
220 | } | |||
239 | 221 | |||
240 | if (clk_disable(sc->sc_clk_ahb) != 0) { | 222 | void | |
241 | aprint_error(": couldn't disable ahb clock\n"); | 223 | sunxi_hdmi_doreset(void) | |
242 | return; | 224 | { | |
225 | device_t dev; | |||
226 | struct sunxi_hdmi_softc *sc; | |||
227 | int error; | |||
228 | ||||
229 | for (int i = 0;;i++) { | |||
230 | dev = device_find_by_driver_unit("sunxihdmi", i); | |||
231 | if (dev == NULL) | |||
232 | return; | |||
233 | sc = device_private(dev); | |||
234 | ||||
235 | error = clk_disable(sc->sc_clk_mod); | |||
236 | if (error) { | |||
237 | aprint_error_dev(dev, ": couldn't disable mod clock\n"); | |||
238 | return; | |||
239 | } | |||
240 | ||||
241 | #if defined(SUNXI_HDMI_DEBUG) | |||
242 | sunxi_hdmi_dump_regs(); | |||
243 | #endif | |||
244 | ||||
245 | /* | |||
246 | * reset device, in case it has been setup by firmware in an | |||
247 | * incompatible way | |||
248 | */ | |||
249 | for (int j = 0; j <= 0x500; j += 4) { | |||
250 | HDMI_WRITE(sc, j, 0); | |||
251 | } | |||
252 | ||||
253 | if (clk_disable(sc->sc_clk_ahb) != 0) { | |||
254 | aprint_error_dev(dev, ": couldn't disable ahb clock\n"); | |||
255 | return; | |||
256 | } | |||
243 | } | 257 | } | |
244 | } | 258 | } | |
245 | 259 | |||
246 | static void | 260 | static void | |
247 | sunxi_hdmi_i2c_init(struct sunxi_hdmi_softc *sc) | 261 | sunxi_hdmi_i2c_init(struct sunxi_hdmi_softc *sc) | |
248 | { | 262 | { | |
249 | struct i2c_controller *ic = &sc->sc_ic; | 263 | struct i2c_controller *ic = &sc->sc_ic; | |
250 | 264 | |||
251 | mutex_init(&sc->sc_ic_lock, MUTEX_DEFAULT, IPL_NONE); | 265 | mutex_init(&sc->sc_ic_lock, MUTEX_DEFAULT, IPL_NONE); | |
252 | 266 | |||
253 | ic->ic_cookie = sc; | 267 | ic->ic_cookie = sc; | |
254 | ic->ic_acquire_bus = sunxi_hdmi_i2c_acquire_bus; | 268 | ic->ic_acquire_bus = sunxi_hdmi_i2c_acquire_bus; | |
255 | ic->ic_release_bus = sunxi_hdmi_i2c_release_bus; | 269 | ic->ic_release_bus = sunxi_hdmi_i2c_release_bus; |
--- src/sys/arch/arm/sunxi/sunxi_tcon.c 2018/04/07 18:09:33 1.6
+++ src/sys/arch/arm/sunxi/sunxi_tcon.c 2018/06/01 17:18:44 1.7
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: sunxi_tcon.c,v 1.6 2018/04/07 18:09:33 bouyer Exp $ */ | 1 | /* $NetBSD: sunxi_tcon.c,v 1.7 2018/06/01 17:18:44 bouyer Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2018 Manuel Bouyer <bouyer@antioche.eu.org> | 4 | * Copyright (c) 2018 Manuel Bouyer <bouyer@antioche.eu.org> | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> | 7 | * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> | |
8 | * All rights reserved. | 8 | * All rights reserved. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -20,27 +20,27 @@ | @@ -20,27 +20,27 @@ | |||
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | __KERNEL_RCSID(0, "$NetBSD: sunxi_tcon.c,v 1.6 2018/04/07 18:09:33 bouyer Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: sunxi_tcon.c,v 1.7 2018/06/01 17:18:44 bouyer Exp $"); | |
34 | 34 | |||
35 | #include <sys/param.h> | 35 | #include <sys/param.h> | |
36 | #include <sys/bus.h> | 36 | #include <sys/bus.h> | |
37 | #include <sys/device.h> | 37 | #include <sys/device.h> | |
38 | #include <sys/intr.h> | 38 | #include <sys/intr.h> | |
39 | #include <sys/systm.h> | 39 | #include <sys/systm.h> | |
40 | #include <sys/kernel.h> | 40 | #include <sys/kernel.h> | |
41 | #include <sys/mutex.h> | 41 | #include <sys/mutex.h> | |
42 | #include <sys/condvar.h> | 42 | #include <sys/condvar.h> | |
43 | 43 | |||
44 | #include <dev/fdt/fdtvar.h> | 44 | #include <dev/fdt/fdtvar.h> | |
45 | #include <dev/fdt/fdt_port.h> | 45 | #include <dev/fdt/fdt_port.h> | |
46 | #include <dev/fdt/panel_fdt.h> | 46 | #include <dev/fdt/panel_fdt.h> | |
@@ -55,26 +55,27 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_tcon.c | @@ -55,26 +55,27 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_tcon.c | |||
55 | enum sunxi_tcon_type { | 55 | enum sunxi_tcon_type { | |
56 | TCON_A10 = 1, | 56 | TCON_A10 = 1, | |
57 | }; | 57 | }; | |
58 | 58 | |||
59 | struct sunxi_tcon_softc { | 59 | struct sunxi_tcon_softc { | |
60 | device_t sc_dev; | 60 | device_t sc_dev; | |
61 | enum sunxi_tcon_type sc_type; | 61 | enum sunxi_tcon_type sc_type; | |
62 | int sc_phandle; | 62 | int sc_phandle; | |
63 | bus_space_tag_t sc_bst; | 63 | bus_space_tag_t sc_bst; | |
64 | bus_space_handle_t sc_bsh; | 64 | bus_space_handle_t sc_bsh; | |
65 | struct clk *sc_clk_ahb; | 65 | struct clk *sc_clk_ahb; | |
66 | struct clk *sc_clk_ch0; | 66 | struct clk *sc_clk_ch0; | |
67 | struct clk *sc_clk_ch1; | 67 | struct clk *sc_clk_ch1; | |
68 | struct fdtbus_reset *sc_rst, *sc_lvds_rst; | |||
68 | unsigned int sc_output_type; | 69 | unsigned int sc_output_type; | |
69 | #define OUTPUT_HDMI 0 | 70 | #define OUTPUT_HDMI 0 | |
70 | #define OUTPUT_LVDS 1 | 71 | #define OUTPUT_LVDS 1 | |
71 | #define OUTPUT_VGA 2 | 72 | #define OUTPUT_VGA 2 | |
72 | struct fdt_device_ports sc_ports; | 73 | struct fdt_device_ports sc_ports; | |
73 | int sc_unit; /* tcon0 or tcon1 */ | 74 | int sc_unit; /* tcon0 or tcon1 */ | |
74 | struct fdt_endpoint *sc_in_ep; | 75 | struct fdt_endpoint *sc_in_ep; | |
75 | struct fdt_endpoint *sc_in_rep; | 76 | struct fdt_endpoint *sc_in_rep; | |
76 | struct fdt_endpoint *sc_out_ep; | 77 | struct fdt_endpoint *sc_out_ep; | |
77 | }; | 78 | }; | |
78 | 79 | |||
79 | static bus_space_handle_t tcon_mux_bsh; | 80 | static bus_space_handle_t tcon_mux_bsh; | |
80 | static bool tcon_mux_inited = false; | 81 | static bool tcon_mux_inited = false; | |
@@ -110,28 +111,26 @@ sunxi_tcon_match(device_t parent, cfdata | @@ -110,28 +111,26 @@ sunxi_tcon_match(device_t parent, cfdata | |||
110 | struct fdt_attach_args * const faa = aux; | 111 | struct fdt_attach_args * const faa = aux; | |
111 | 112 | |||
112 | return of_match_compat_data(faa->faa_phandle, compat_data); | 113 | return of_match_compat_data(faa->faa_phandle, compat_data); | |
113 | } | 114 | } | |
114 | 115 | |||
115 | static void | 116 | static void | |
116 | sunxi_tcon_attach(device_t parent, device_t self, void *aux) | 117 | sunxi_tcon_attach(device_t parent, device_t self, void *aux) | |
117 | { | 118 | { | |
118 | struct sunxi_tcon_softc *sc = device_private(self); | 119 | struct sunxi_tcon_softc *sc = device_private(self); | |
119 | struct fdt_attach_args * const faa = aux; | 120 | struct fdt_attach_args * const faa = aux; | |
120 | const int phandle = faa->faa_phandle; | 121 | const int phandle = faa->faa_phandle; | |
121 | bus_addr_t addr; | 122 | bus_addr_t addr; | |
122 | bus_size_t size; | 123 | bus_size_t size; | |
123 | struct fdtbus_reset *rst, *lvds_rst; | |||
124 | ||||
125 | 124 | |||
126 | sc->sc_dev = self; | 125 | sc->sc_dev = self; | |
127 | sc->sc_phandle = phandle; | 126 | sc->sc_phandle = phandle; | |
128 | sc->sc_bst = faa->faa_bst; | 127 | sc->sc_bst = faa->faa_bst; | |
129 | 128 | |||
130 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | 129 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { | |
131 | aprint_error(": couldn't get registers\n"); | 130 | aprint_error(": couldn't get registers\n"); | |
132 | } | 131 | } | |
133 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | 132 | if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { | |
134 | aprint_error(": couldn't map registers\n"); | 133 | aprint_error(": couldn't map registers\n"); | |
135 | return; | 134 | return; | |
136 | } | 135 | } | |
137 | 136 | |||
@@ -139,104 +138,121 @@ sunxi_tcon_attach(device_t parent, devic | @@ -139,104 +138,121 @@ sunxi_tcon_attach(device_t parent, devic | |||
139 | sc->sc_clk_ch0 = fdtbus_clock_get(phandle, "tcon-ch0"); | 138 | sc->sc_clk_ch0 = fdtbus_clock_get(phandle, "tcon-ch0"); | |
140 | sc->sc_clk_ch1 = fdtbus_clock_get(phandle, "tcon-ch1"); | 139 | sc->sc_clk_ch1 = fdtbus_clock_get(phandle, "tcon-ch1"); | |
141 | 140 | |||
142 | if (sc->sc_clk_ahb == NULL || sc->sc_clk_ch0 == NULL | 141 | if (sc->sc_clk_ahb == NULL || sc->sc_clk_ch0 == NULL | |
143 | || sc->sc_clk_ch1 == NULL) { | 142 | || sc->sc_clk_ch1 == NULL) { | |
144 | aprint_error(": couldn't get clocks\n"); | 143 | aprint_error(": couldn't get clocks\n"); | |
145 | aprint_debug_dev(self, "clk ahb %s tcon-ch0 %s tcon-ch1 %s\n", | 144 | aprint_debug_dev(self, "clk ahb %s tcon-ch0 %s tcon-ch1 %s\n", | |
146 | sc->sc_clk_ahb == NULL ? "missing" : "present", | 145 | sc->sc_clk_ahb == NULL ? "missing" : "present", | |
147 | sc->sc_clk_ch0 == NULL ? "missing" : "present", | 146 | sc->sc_clk_ch0 == NULL ? "missing" : "present", | |
148 | sc->sc_clk_ch1 == NULL ? "missing" : "present"); | 147 | sc->sc_clk_ch1 == NULL ? "missing" : "present"); | |
149 | return; | 148 | return; | |
150 | } | 149 | } | |
151 | 150 | |||
152 | rst = fdtbus_reset_get(phandle, "lcd"); | 151 | sc->sc_rst = fdtbus_reset_get(phandle, "lcd"); | |
153 | if (rst == NULL) { | 152 | if (sc->sc_rst == NULL) { | |
154 | aprint_error(": couldn't get lcd reset\n"); | 153 | aprint_error(": couldn't get lcd reset\n"); | |
155 | return; | 154 | return; | |
156 | } | 155 | } | |
157 | 156 | |||
158 | lvds_rst = fdtbus_reset_get(phandle, "lvds"); | 157 | sc->sc_lvds_rst = fdtbus_reset_get(phandle, "lvds"); | |
159 | ||||
160 | if (clk_disable(sc->sc_clk_ahb) != 0) { | |||
161 | aprint_error(": couldn't disable ahb clock\n"); | |||
162 | return; | |||
163 | } | |||
164 | if (clk_disable(sc->sc_clk_ch0) != 0) { | |||
165 | aprint_error(": couldn't disable ch0 clock\n"); | |||
166 | return; | |||
167 | } | |||
168 | ||||
169 | if (clk_disable(sc->sc_clk_ch1) != 0) { | |||
170 | aprint_error(": couldn't disable ch1 clock\n"); | |||
171 | return; | |||
172 | } | |||
173 | ||||
174 | if (fdtbus_reset_assert(rst) != 0) { | |||
175 | aprint_error(": couldn't assert lcd reset\n"); | |||
176 | return; | |||
177 | } | |||
178 | if (lvds_rst != NULL) { | |||
179 | if (fdtbus_reset_assert(lvds_rst) != 0) { | |||
180 | aprint_error(": couldn't assert lvds reset\n"); | |||
181 | return; | |||
182 | } | |||
183 | } | |||
184 | delay(1); | |||
185 | if (fdtbus_reset_deassert(rst) != 0) { | |||
186 | aprint_error(": couldn't de-assert lcd reset\n"); | |||
187 | return; | |||
188 | } | |||
189 | if (lvds_rst != NULL) { | |||
190 | if (fdtbus_reset_deassert(lvds_rst) != 0) { | |||
191 | aprint_error(": couldn't de-assert lvds reset\n"); | |||
192 | return; | |||
193 | } | |||
194 | } | |||
195 | ||||
196 | if (clk_enable(sc->sc_clk_ahb) != 0) { | |||
197 | aprint_error(": couldn't enable ahb clock\n"); | |||
198 | return; | |||
199 | } | |||
200 | 158 | |||
201 | sc->sc_type = of_search_compatible(faa->faa_phandle, compat_data)->data; | 159 | sc->sc_type = of_search_compatible(faa->faa_phandle, compat_data)->data; | |
202 | 160 | |||
203 | aprint_naive("\n"); | 161 | aprint_naive("\n"); | |
204 | aprint_normal(": LCD/TV timing controller (%s)\n", | 162 | aprint_normal(": LCD/TV timing controller (%s)\n", | |
205 | fdtbus_get_string(phandle, "name")); | 163 | fdtbus_get_string(phandle, "name")); | |
206 | 164 | |||
207 | sc->sc_unit = -1; | 165 | sc->sc_unit = -1; | |
208 | sc->sc_ports.dp_ep_connect = sunxi_tcon_ep_connect; | 166 | sc->sc_ports.dp_ep_connect = sunxi_tcon_ep_connect; | |
209 | sc->sc_ports.dp_ep_activate = sunxi_tcon_ep_activate; | 167 | sc->sc_ports.dp_ep_activate = sunxi_tcon_ep_activate; | |
210 | sc->sc_ports.dp_ep_enable = sunxi_tcon_ep_enable; | 168 | sc->sc_ports.dp_ep_enable = sunxi_tcon_ep_enable; | |
211 | fdt_ports_register(&sc->sc_ports, self, phandle, EP_OTHER); | 169 | fdt_ports_register(&sc->sc_ports, self, phandle, EP_OTHER); | |
170 | } | |||
212 | 171 | |||
213 | TCON_WRITE(sc, SUNXI_TCON_GINT0_REG, 0); | 172 | void | |
214 | TCON_WRITE(sc, SUNXI_TCON_GINT1_REG, | 173 | sunxi_tcon_doreset(void) | |
215 | __SHIFTIN(0x20, SUNXI_TCON_GINT1_TCON0_LINENO)); | 174 | { | |
216 | TCON_WRITE(sc, SUNXI_TCON0_DCLK_REG, 0xf0000000); | 175 | device_t dev; | |
217 | TCON_WRITE(sc, SUNXI_TCON0_LVDS_IF_REG, 0x0); | 176 | struct sunxi_tcon_softc *sc; | |
218 | TCON_WRITE(sc, SUNXI_TCON0_CTL_REG, 0); | 177 | for (int i = 0;;i++) { | |
219 | TCON_WRITE(sc, SUNXI_TCON0_IO_TRI_REG, 0xffffffff); | 178 | dev = device_find_by_driver_unit("sunxitcon", i); | |
220 | TCON_WRITE(sc, SUNXI_TCON1_CTL_REG, 0); | 179 | if (dev == NULL) | |
221 | TCON_WRITE(sc, SUNXI_TCON1_IO_TRI_REG, 0xffffffff); | 180 | return; | |
222 | TCON_WRITE(sc, SUNXI_TCON_GCTL_REG, 0); | 181 | sc = device_private(dev); | |
223 | 182 | |||
224 | /* clock needed for the mux in unit 0 */ | |||
225 | if (sc->sc_unit != 0) { | |||
226 | if (clk_disable(sc->sc_clk_ahb) != 0) { | 183 | if (clk_disable(sc->sc_clk_ahb) != 0) { | |
227 | aprint_error(": couldn't disable ahb clock\n"); | 184 | aprint_error_dev(dev, ": couldn't disable ahb clock\n"); | |
185 | return; | |||
186 | } | |||
187 | if (clk_disable(sc->sc_clk_ch0) != 0) { | |||
188 | aprint_error_dev(dev, ": couldn't disable ch0 clock\n"); | |||
189 | return; | |||
190 | } | |||
191 | ||||
192 | if (clk_disable(sc->sc_clk_ch1) != 0) { | |||
193 | aprint_error_dev(dev, ": couldn't disable ch1 clock\n"); | |||
194 | return; | |||
195 | } | |||
196 | ||||
197 | if (fdtbus_reset_assert(sc->sc_rst) != 0) { | |||
198 | aprint_error_dev(dev, ": couldn't assert lcd reset\n"); | |||
199 | return; | |||
200 | } | |||
201 | if (sc->sc_lvds_rst != NULL) { | |||
202 | if (fdtbus_reset_assert(sc->sc_lvds_rst) != 0) { | |||
203 | aprint_error_dev(dev, | |||
204 | ": couldn't assert lvds reset\n"); | |||
205 | return; | |||
206 | } | |||
207 | } | |||
208 | delay(1); | |||
209 | if (fdtbus_reset_deassert(sc->sc_rst) != 0) { | |||
210 | aprint_error_dev(dev, | |||
211 | ": couldn't de-assert lcd reset\n"); | |||
228 | return; | 212 | return; | |
229 | } | 213 | } | |
214 | if (sc->sc_lvds_rst != NULL) { | |||
215 | if (fdtbus_reset_deassert(sc->sc_lvds_rst) != 0) { | |||
216 | aprint_error_dev(dev, | |||
217 | ": couldn't de-assert lvds reset\n"); | |||
218 | return; | |||
219 | } | |||
220 | } | |||
221 | ||||
222 | if (clk_enable(sc->sc_clk_ahb) != 0) { | |||
223 | aprint_error_dev(dev, ": couldn't enable ahb clock\n"); | |||
224 | return; | |||
225 | } | |||
226 | ||||
227 | TCON_WRITE(sc, SUNXI_TCON_GINT0_REG, 0); | |||
228 | TCON_WRITE(sc, SUNXI_TCON_GINT1_REG, | |||
229 | __SHIFTIN(0x20, SUNXI_TCON_GINT1_TCON0_LINENO)); | |||
230 | TCON_WRITE(sc, SUNXI_TCON0_DCLK_REG, 0xf0000000); | |||
231 | TCON_WRITE(sc, SUNXI_TCON0_LVDS_IF_REG, 0x0); | |||
232 | TCON_WRITE(sc, SUNXI_TCON0_CTL_REG, 0); | |||
233 | TCON_WRITE(sc, SUNXI_TCON0_IO_TRI_REG, 0xffffffff); | |||
234 | TCON_WRITE(sc, SUNXI_TCON1_CTL_REG, 0); | |||
235 | TCON_WRITE(sc, SUNXI_TCON1_IO_TRI_REG, 0xffffffff); | |||
236 | TCON_WRITE(sc, SUNXI_TCON_GCTL_REG, 0); | |||
237 | ||||
238 | /* clock needed for the mux in unit 0 */ | |||
239 | if (sc->sc_unit != 0) { | |||
240 | if (clk_disable(sc->sc_clk_ahb) != 0) { | |||
241 | aprint_error_dev(dev, | |||
242 | ": couldn't disable ahb clock\n"); | |||
243 | return; | |||
244 | } | |||
245 | } | |||
230 | } | 246 | } | |
231 | } | 247 | } | |
232 | 248 | |||
233 | static void | 249 | static void | |
234 | sunxi_tcon_ep_connect(device_t self, struct fdt_endpoint *ep, bool connect) | 250 | sunxi_tcon_ep_connect(device_t self, struct fdt_endpoint *ep, bool connect) | |
235 | { | 251 | { | |
236 | struct sunxi_tcon_softc *sc = device_private(self); | 252 | struct sunxi_tcon_softc *sc = device_private(self); | |
237 | struct fdt_endpoint *rep = fdt_endpoint_remote(ep); | 253 | struct fdt_endpoint *rep = fdt_endpoint_remote(ep); | |
238 | int rep_idx = fdt_endpoint_index(rep); | 254 | int rep_idx = fdt_endpoint_index(rep); | |
239 | 255 | |||
240 | KASSERT(device_is_a(self, "sunxitcon")); | 256 | KASSERT(device_is_a(self, "sunxitcon")); | |
241 | if (!connect) { | 257 | if (!connect) { | |
242 | aprint_error_dev(self, "endpoint disconnect not supported\n"); | 258 | aprint_error_dev(self, "endpoint disconnect not supported\n"); |