1*8e90f9edSthorpej /* $NetBSD: meson_genfb.c,v 1.2 2021/01/27 03:10:18 thorpej Exp $ */
2c4d695ffSjmcneill
3c4d695ffSjmcneill /*-
4c4d695ffSjmcneill * Copyright (c) 2015-2019 Jared McNeill <jmcneill@invisible.ca>
5c4d695ffSjmcneill * All rights reserved.
6c4d695ffSjmcneill *
7c4d695ffSjmcneill * Redistribution and use in source and binary forms, with or without
8c4d695ffSjmcneill * modification, are permitted provided that the following conditions
9c4d695ffSjmcneill * are met:
10c4d695ffSjmcneill * 1. Redistributions of source code must retain the above copyright
11c4d695ffSjmcneill * notice, this list of conditions and the following disclaimer.
12c4d695ffSjmcneill * 2. Redistributions in binary form must reproduce the above copyright
13c4d695ffSjmcneill * notice, this list of conditions and the following disclaimer in the
14c4d695ffSjmcneill * documentation and/or other materials provided with the distribution.
15c4d695ffSjmcneill *
16c4d695ffSjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17c4d695ffSjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18c4d695ffSjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19c4d695ffSjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20c4d695ffSjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21c4d695ffSjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22c4d695ffSjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23c4d695ffSjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24c4d695ffSjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25c4d695ffSjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26c4d695ffSjmcneill * POSSIBILITY OF SUCH DAMAGE.
27c4d695ffSjmcneill */
28c4d695ffSjmcneill
29c4d695ffSjmcneill /*
30c4d695ffSjmcneill * Generic framebuffer console driver
31c4d695ffSjmcneill */
32c4d695ffSjmcneill
33c4d695ffSjmcneill #include "opt_wsdisplay_compat.h"
34c4d695ffSjmcneill
35c4d695ffSjmcneill #include <sys/cdefs.h>
36*8e90f9edSthorpej __KERNEL_RCSID(0, "$NetBSD: meson_genfb.c,v 1.2 2021/01/27 03:10:18 thorpej Exp $");
37c4d695ffSjmcneill
38c4d695ffSjmcneill #include <sys/param.h>
39c4d695ffSjmcneill #include <sys/types.h>
40c4d695ffSjmcneill #include <sys/systm.h>
41c4d695ffSjmcneill #include <sys/device.h>
42c4d695ffSjmcneill #include <sys/conf.h>
43c4d695ffSjmcneill #include <sys/bus.h>
44c4d695ffSjmcneill #include <sys/kmem.h>
45c4d695ffSjmcneill #include <sys/sysctl.h>
46c4d695ffSjmcneill
47c4d695ffSjmcneill #include <dev/fdt/fdtvar.h>
48c4d695ffSjmcneill
49c4d695ffSjmcneill #include <arm/amlogic/meson_canvasreg.h>
50c4d695ffSjmcneill #include <arm/amlogic/meson_vpureg.h>
51c4d695ffSjmcneill #include <arm/amlogic/meson_hdmireg.h>
52c4d695ffSjmcneill
53c4d695ffSjmcneill #include <dev/wsfb/genfbvar.h>
54c4d695ffSjmcneill
55*8e90f9edSthorpej static const struct device_compatible_entry compat_data[] = {
56*8e90f9edSthorpej { .compat = "amlogic,meson8b-fb" },
57*8e90f9edSthorpej DEVICE_COMPAT_EOL
58c4d695ffSjmcneill };
59c4d695ffSjmcneill
60c4d695ffSjmcneill #define AMLOGIC_GENFB_DEFAULT_DEPTH 16
61c4d695ffSjmcneill
62c4d695ffSjmcneill /* Map CEA-861-D video code (VIC) to framebuffer dimensions */
63c4d695ffSjmcneill static const struct meson_genfb_vic2mode {
64c4d695ffSjmcneill u_int vic;
65c4d695ffSjmcneill u_int width;
66c4d695ffSjmcneill u_int height;
67c4d695ffSjmcneill u_int flags;
68c4d695ffSjmcneill #define INTERLACE __BIT(0)
69c4d695ffSjmcneill #define DBLSCAN __BIT(1)
70c4d695ffSjmcneill } meson_genfb_modes[] = {
71c4d695ffSjmcneill { 1, 640, 480 },
72c4d695ffSjmcneill { 2, 720, 480 },
73c4d695ffSjmcneill { 3, 720, 480 },
74c4d695ffSjmcneill { 4, 1280, 720 },
75c4d695ffSjmcneill { 5, 1920, 1080, INTERLACE },
76c4d695ffSjmcneill { 6, 720, 480, DBLSCAN | INTERLACE },
77c4d695ffSjmcneill { 7, 720, 480, DBLSCAN | INTERLACE },
78c4d695ffSjmcneill { 8, 720, 240, DBLSCAN },
79c4d695ffSjmcneill { 9, 720, 240, DBLSCAN },
80c4d695ffSjmcneill { 16, 1920, 1080 },
81c4d695ffSjmcneill { 17, 720, 576 },
82c4d695ffSjmcneill { 18, 720, 576 },
83c4d695ffSjmcneill { 19, 1280, 720 },
84c4d695ffSjmcneill { 20, 1920, 1080, INTERLACE },
85c4d695ffSjmcneill { 31, 1920, 1080 },
86c4d695ffSjmcneill { 32, 1920, 1080 },
87c4d695ffSjmcneill { 33, 1920, 1080 },
88c4d695ffSjmcneill { 34, 1920, 1080 },
89c4d695ffSjmcneill { 39, 1920, 1080, INTERLACE },
90c4d695ffSjmcneill };
91c4d695ffSjmcneill
92c4d695ffSjmcneill struct meson_genfb_softc {
93c4d695ffSjmcneill struct genfb_softc sc_gen;
94c4d695ffSjmcneill bus_space_tag_t sc_bst;
95c4d695ffSjmcneill bus_space_handle_t sc_cav_bsh;
96c4d695ffSjmcneill bus_space_handle_t sc_hdmi_bsh;
97c4d695ffSjmcneill bus_space_handle_t sc_vpu_bsh;
98c4d695ffSjmcneill bus_dma_tag_t sc_dmat;
99c4d695ffSjmcneill
100c4d695ffSjmcneill kmutex_t sc_lock;
101c4d695ffSjmcneill
102c4d695ffSjmcneill u_int sc_scale;
103c4d695ffSjmcneill
104c4d695ffSjmcneill bus_dma_segment_t sc_dmasegs[1];
105c4d695ffSjmcneill bus_size_t sc_dmasize;
106c4d695ffSjmcneill bus_dmamap_t sc_dmamap;
107c4d695ffSjmcneill void *sc_dmap;
108c4d695ffSjmcneill
109c4d695ffSjmcneill uint32_t sc_wstype;
110c4d695ffSjmcneill
111c4d695ffSjmcneill struct sysctllog *sc_sysctllog;
112c4d695ffSjmcneill int sc_node_scale;
113c4d695ffSjmcneill };
114c4d695ffSjmcneill
115c4d695ffSjmcneill static int meson_genfb_match(device_t, cfdata_t, void *);
116c4d695ffSjmcneill static void meson_genfb_attach(device_t, device_t, void *);
117c4d695ffSjmcneill
118c4d695ffSjmcneill static int meson_genfb_ioctl(void *, void *, u_long, void *, int, lwp_t *);
119c4d695ffSjmcneill static paddr_t meson_genfb_mmap(void *, void *, off_t, int);
120c4d695ffSjmcneill static bool meson_genfb_shutdown(device_t, int);
121c4d695ffSjmcneill
122c4d695ffSjmcneill static void meson_genfb_canvas_config(struct meson_genfb_softc *);
123c4d695ffSjmcneill static void meson_genfb_osd_config(struct meson_genfb_softc *);
124c4d695ffSjmcneill static void meson_genfb_scaler_config(struct meson_genfb_softc *);
125c4d695ffSjmcneill
126c4d695ffSjmcneill static void meson_genfb_init(struct meson_genfb_softc *);
127c4d695ffSjmcneill static int meson_genfb_alloc_videomem(struct meson_genfb_softc *);
128c4d695ffSjmcneill
129c4d695ffSjmcneill static int meson_genfb_scale_helper(SYSCTLFN_PROTO);
130c4d695ffSjmcneill
131c4d695ffSjmcneill void meson_genfb_set_console_dev(device_t);
132c4d695ffSjmcneill void meson_genfb_ddb_trap_callback(int);
133c4d695ffSjmcneill
134c4d695ffSjmcneill static int meson_genfb_console_phandle = -1;
135c4d695ffSjmcneill static device_t meson_genfb_console_dev = NULL;
136c4d695ffSjmcneill
137c4d695ffSjmcneill CFATTACH_DECL_NEW(meson_genfb, sizeof(struct meson_genfb_softc),
138c4d695ffSjmcneill meson_genfb_match, meson_genfb_attach, NULL, NULL);
139c4d695ffSjmcneill
140c4d695ffSjmcneill static inline uint32_t
meson_genfb_hdmi_read_4(struct meson_genfb_softc * sc,uint32_t addr)141c4d695ffSjmcneill meson_genfb_hdmi_read_4(struct meson_genfb_softc *sc, uint32_t addr)
142c4d695ffSjmcneill {
143c4d695ffSjmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_ADDR_REG, addr);
144c4d695ffSjmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_ADDR_REG, addr);
145c4d695ffSjmcneill return bus_space_read_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_DATA_REG);
146c4d695ffSjmcneill }
147c4d695ffSjmcneill
148c4d695ffSjmcneill static __unused inline void
meson_genfb_hdmi_write_4(struct meson_genfb_softc * sc,uint32_t addr,uint32_t data)149c4d695ffSjmcneill meson_genfb_hdmi_write_4(struct meson_genfb_softc *sc, uint32_t addr,
150c4d695ffSjmcneill uint32_t data)
151c4d695ffSjmcneill {
152c4d695ffSjmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_ADDR_REG, addr);
153c4d695ffSjmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_ADDR_REG, addr);
154c4d695ffSjmcneill bus_space_write_4(sc->sc_bst, sc->sc_hdmi_bsh, HDMI_DATA_REG, data);
155c4d695ffSjmcneill }
156c4d695ffSjmcneill
157c4d695ffSjmcneill #define HDMI_READ meson_genfb_hdmi_read_4
158c4d695ffSjmcneill #define HDMI_WRITE meson_genfb_hdmi_write_4
159c4d695ffSjmcneill
160c4d695ffSjmcneill #define VPU_READ(sc, reg) \
161c4d695ffSjmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_vpu_bsh, (reg))
162c4d695ffSjmcneill #define VPU_WRITE(sc, reg, val) \
163c4d695ffSjmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_vpu_bsh, (reg), (val))
164c4d695ffSjmcneill
165c4d695ffSjmcneill #define CAV_READ(sc, reg) \
166c4d695ffSjmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_cav_bsh, (reg))
167c4d695ffSjmcneill #define CAV_WRITE(sc, reg, val) \
168c4d695ffSjmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_cav_bsh, (reg), (val))
169c4d695ffSjmcneill
170c4d695ffSjmcneill static int
meson_genfb_match(device_t parent,cfdata_t match,void * aux)171c4d695ffSjmcneill meson_genfb_match(device_t parent, cfdata_t match, void *aux)
172c4d695ffSjmcneill {
173c4d695ffSjmcneill struct fdt_attach_args * const faa = aux;
174c4d695ffSjmcneill
175*8e90f9edSthorpej return of_compatible_match(faa->faa_phandle, compat_data);
176c4d695ffSjmcneill }
177c4d695ffSjmcneill
178c4d695ffSjmcneill static void
meson_genfb_attach(device_t parent,device_t self,void * aux)179c4d695ffSjmcneill meson_genfb_attach(device_t parent, device_t self, void *aux)
180c4d695ffSjmcneill {
181c4d695ffSjmcneill struct meson_genfb_softc *sc = device_private(self);
182c4d695ffSjmcneill struct fdt_attach_args * const faa = aux;
183c4d695ffSjmcneill const int phandle = faa->faa_phandle;
184c4d695ffSjmcneill prop_dictionary_t dict = device_properties(self);
185c4d695ffSjmcneill static const struct genfb_ops zero_ops;
186c4d695ffSjmcneill struct genfb_ops ops = zero_ops;
187c4d695ffSjmcneill bus_addr_t addr[3];
188c4d695ffSjmcneill bus_size_t size[3];
189c4d695ffSjmcneill
190c4d695ffSjmcneill for (int i = 0; i < 3; i++) {
191c4d695ffSjmcneill if (fdtbus_get_reg(phandle, i, &addr[i], &size[i]) != 0) {
192c4d695ffSjmcneill aprint_error(": couldn't get register #%d\n", i);
193c4d695ffSjmcneill return;
194c4d695ffSjmcneill }
195c4d695ffSjmcneill }
196c4d695ffSjmcneill
197c4d695ffSjmcneill sc->sc_gen.sc_dev = self;
198c4d695ffSjmcneill sc->sc_bst = faa->faa_bst;
199c4d695ffSjmcneill sc->sc_dmat = faa->faa_dmat;
200c4d695ffSjmcneill if (bus_space_map(sc->sc_bst, addr[0], size[0], 0, &sc->sc_cav_bsh) != 0 ||
201c4d695ffSjmcneill bus_space_map(sc->sc_bst, addr[1], size[1], 0, &sc->sc_hdmi_bsh) != 0 ||
202c4d695ffSjmcneill bus_space_map(sc->sc_bst, addr[2], size[2], 0, &sc->sc_vpu_bsh) != 0) {
203c4d695ffSjmcneill aprint_error(": couldn't map registers\n");
204c4d695ffSjmcneill return;
205c4d695ffSjmcneill }
206c4d695ffSjmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
207c4d695ffSjmcneill
208c4d695ffSjmcneill meson_genfb_init(sc);
209c4d695ffSjmcneill
210c4d695ffSjmcneill sc->sc_wstype = WSDISPLAY_TYPE_MESON;
211c4d695ffSjmcneill
212c4d695ffSjmcneill aprint_naive("\n");
213c4d695ffSjmcneill aprint_normal("\n");
214c4d695ffSjmcneill
215c4d695ffSjmcneill genfb_init(&sc->sc_gen);
216c4d695ffSjmcneill
217c4d695ffSjmcneill if (sc->sc_gen.sc_width == 0 ||
218c4d695ffSjmcneill sc->sc_gen.sc_fbsize == 0) {
219c4d695ffSjmcneill aprint_normal_dev(self, "disabled\n");
220c4d695ffSjmcneill return;
221c4d695ffSjmcneill }
222c4d695ffSjmcneill
223c4d695ffSjmcneill pmf_device_register1(self, NULL, NULL, meson_genfb_shutdown);
224c4d695ffSjmcneill
225c4d695ffSjmcneill #ifdef WSDISPLAY_MULTICONS
226c4d695ffSjmcneill const bool is_console = true;
227c4d695ffSjmcneill #else
228c4d695ffSjmcneill const bool is_console = phandle == meson_genfb_console_phandle;
229c4d695ffSjmcneill if (is_console)
230c4d695ffSjmcneill aprint_normal_dev(self, "switching to framebuffer console\n");
231c4d695ffSjmcneill #endif
232c4d695ffSjmcneill prop_dictionary_set_bool(dict, "is_console", is_console);
233c4d695ffSjmcneill
234c4d695ffSjmcneill memset(&ops, 0, sizeof(ops));
235c4d695ffSjmcneill ops.genfb_ioctl = meson_genfb_ioctl;
236c4d695ffSjmcneill ops.genfb_mmap = meson_genfb_mmap;
237c4d695ffSjmcneill
238c4d695ffSjmcneill genfb_attach(&sc->sc_gen, &ops);
239c4d695ffSjmcneill }
240c4d695ffSjmcneill
241c4d695ffSjmcneill static int
meson_genfb_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,lwp_t * l)242c4d695ffSjmcneill meson_genfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l)
243c4d695ffSjmcneill {
244c4d695ffSjmcneill struct meson_genfb_softc *sc = v;
245c4d695ffSjmcneill struct wsdisplayio_bus_id *busid;
246c4d695ffSjmcneill
247c4d695ffSjmcneill switch (cmd) {
248c4d695ffSjmcneill case WSDISPLAYIO_GTYPE:
249c4d695ffSjmcneill *(u_int *)data = sc->sc_wstype;
250c4d695ffSjmcneill return 0;
251c4d695ffSjmcneill case WSDISPLAYIO_GET_BUSID:
252c4d695ffSjmcneill busid = data;
253c4d695ffSjmcneill busid->bus_type = WSDISPLAYIO_BUS_SOC;
254c4d695ffSjmcneill return 0;
255c4d695ffSjmcneill case WSDISPLAYIO_GET_FBINFO:
256c4d695ffSjmcneill {
257c4d695ffSjmcneill struct wsdisplayio_fbinfo *fbi = data;
258c4d695ffSjmcneill struct rasops_info *ri = &sc->sc_gen.vd.active->scr_ri;
259c4d695ffSjmcneill int ret;
260c4d695ffSjmcneill
261c4d695ffSjmcneill ret = wsdisplayio_get_fbinfo(ri, fbi);
262c4d695ffSjmcneill fbi->fbi_flags |= WSFB_VRAM_IS_RAM;
263c4d695ffSjmcneill return ret;
264c4d695ffSjmcneill }
265c4d695ffSjmcneill default:
266c4d695ffSjmcneill return EPASSTHROUGH;
267c4d695ffSjmcneill }
268c4d695ffSjmcneill }
269c4d695ffSjmcneill
270c4d695ffSjmcneill static paddr_t
meson_genfb_mmap(void * v,void * vs,off_t offset,int prot)271c4d695ffSjmcneill meson_genfb_mmap(void *v, void *vs, off_t offset, int prot)
272c4d695ffSjmcneill {
273c4d695ffSjmcneill struct meson_genfb_softc *sc = v;
274c4d695ffSjmcneill
275c4d695ffSjmcneill if (offset < 0 || offset >= sc->sc_dmasegs[0].ds_len)
276c4d695ffSjmcneill return -1;
277c4d695ffSjmcneill
278c4d695ffSjmcneill return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dmasegs, 1,
279c4d695ffSjmcneill offset, prot, BUS_DMA_PREFETCHABLE);
280c4d695ffSjmcneill }
281c4d695ffSjmcneill
282c4d695ffSjmcneill static bool
meson_genfb_shutdown(device_t self,int flags)283c4d695ffSjmcneill meson_genfb_shutdown(device_t self, int flags)
284c4d695ffSjmcneill {
285c4d695ffSjmcneill genfb_enable_polling(self);
286c4d695ffSjmcneill return true;
287c4d695ffSjmcneill }
288c4d695ffSjmcneill
289c4d695ffSjmcneill static void
meson_genfb_canvas_config(struct meson_genfb_softc * sc)290c4d695ffSjmcneill meson_genfb_canvas_config(struct meson_genfb_softc *sc)
291c4d695ffSjmcneill {
292c4d695ffSjmcneill prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev);
293c4d695ffSjmcneill const paddr_t pa = sc->sc_dmamap->dm_segs[0].ds_addr;
294c4d695ffSjmcneill uint32_t datal, datah, addr;
295c4d695ffSjmcneill u_int width, height, depth;
296c4d695ffSjmcneill
297c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "width", &width);
298c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "height", &height);
299c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "depth", &depth);
300c4d695ffSjmcneill
301c4d695ffSjmcneill const uint32_t w = (width * (depth/8)) >> 3;
302c4d695ffSjmcneill const uint32_t h = height;
303c4d695ffSjmcneill
304c4d695ffSjmcneill datal = CAV_READ(sc, DC_CAV_LUT_DATAL_REG);
305c4d695ffSjmcneill datah = CAV_READ(sc, DC_CAV_LUT_DATAH_REG);
306c4d695ffSjmcneill addr = CAV_READ(sc, DC_CAV_LUT_ADDR_REG);
307c4d695ffSjmcneill
308c4d695ffSjmcneill datal &= ~DC_CAV_LUT_DATAL_WIDTH_L;
309c4d695ffSjmcneill datal |= __SHIFTIN(w & 7, DC_CAV_LUT_DATAL_WIDTH_L);
310c4d695ffSjmcneill datal &= ~DC_CAV_LUT_DATAL_FBADDR;
311c4d695ffSjmcneill datal |= __SHIFTIN(pa >> 3, DC_CAV_LUT_DATAL_FBADDR);
312c4d695ffSjmcneill CAV_WRITE(sc, DC_CAV_LUT_DATAL_REG, datal);
313c4d695ffSjmcneill
314c4d695ffSjmcneill datah &= ~DC_CAV_LUT_DATAH_BLKMODE;
315c4d695ffSjmcneill datah |= __SHIFTIN(DC_CAV_LUT_DATAH_BLKMODE_LINEAR,
316c4d695ffSjmcneill DC_CAV_LUT_DATAH_BLKMODE);
317c4d695ffSjmcneill datah &= ~DC_CAV_LUT_DATAH_WIDTH_H;
318c4d695ffSjmcneill datah |= __SHIFTIN(w >> 3, DC_CAV_LUT_DATAH_WIDTH_H);
319c4d695ffSjmcneill datah &= ~DC_CAV_LUT_DATAH_HEIGHT;
320c4d695ffSjmcneill datah |= __SHIFTIN(h, DC_CAV_LUT_DATAH_HEIGHT);
321c4d695ffSjmcneill CAV_WRITE(sc, DC_CAV_LUT_DATAH_REG, datah);
322c4d695ffSjmcneill
323c4d695ffSjmcneill addr |= DC_CAV_LUT_ADDR_WR_EN;
324c4d695ffSjmcneill CAV_WRITE(sc, DC_CAV_LUT_ADDR_REG, addr);
325c4d695ffSjmcneill }
326c4d695ffSjmcneill
327c4d695ffSjmcneill static void
meson_genfb_osd_config(struct meson_genfb_softc * sc)328c4d695ffSjmcneill meson_genfb_osd_config(struct meson_genfb_softc *sc)
329c4d695ffSjmcneill {
330c4d695ffSjmcneill prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev);
331c4d695ffSjmcneill uint32_t cs, tc, w0, w1, w2, w3, w4;
332c4d695ffSjmcneill u_int width, height, depth;
333c4d695ffSjmcneill bool interlace_p;
334c4d695ffSjmcneill
335c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "width", &width);
336c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "height", &height);
337c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "depth", &depth);
338c4d695ffSjmcneill prop_dictionary_get_bool(cfg, "interlace", &interlace_p);
339c4d695ffSjmcneill
340c4d695ffSjmcneill cs = VPU_READ(sc, VIU_OSD2_CTRL_STAT_REG);
341c4d695ffSjmcneill cs |= VIU_OSD_CTRL_STAT_ENABLE;
342c4d695ffSjmcneill cs &= ~VIU_OSD_CTRL_STAT_GLOBAL_ALPHA;
343c4d695ffSjmcneill cs |= __SHIFTIN(0xff, VIU_OSD_CTRL_STAT_GLOBAL_ALPHA);
344c4d695ffSjmcneill cs |= VIU_OSD_CTRL_STAT_BLK0_ENABLE;
345c4d695ffSjmcneill cs &= ~VIU_OSD_CTRL_STAT_BLK1_ENABLE;
346c4d695ffSjmcneill cs &= ~VIU_OSD_CTRL_STAT_BLK2_ENABLE;
347c4d695ffSjmcneill cs &= ~VIU_OSD_CTRL_STAT_BLK3_ENABLE;
348c4d695ffSjmcneill VPU_WRITE(sc, VIU_OSD2_CTRL_STAT_REG, cs);
349c4d695ffSjmcneill
350c4d695ffSjmcneill tc = __SHIFTIN(0, VIU_OSD_TCOLOR_R) |
351c4d695ffSjmcneill __SHIFTIN(0, VIU_OSD_TCOLOR_G) |
352c4d695ffSjmcneill __SHIFTIN(0, VIU_OSD_TCOLOR_B) |
353c4d695ffSjmcneill __SHIFTIN(255, VIU_OSD_TCOLOR_A);
354c4d695ffSjmcneill VPU_WRITE(sc, VIU_OSD2_TCOLOR_AG0_REG, tc);
355c4d695ffSjmcneill
356c4d695ffSjmcneill w0 = VPU_READ(sc, VIU_OSD2_BLK0_CFG_W0_REG);
357c4d695ffSjmcneill w0 |= VIU_OSD_BLK_CFG_W0_RGB_EN;
358c4d695ffSjmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_TC_ALPHA_EN;
359c4d695ffSjmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE;
360c4d695ffSjmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_COLOR_MATRIX;
361c4d695ffSjmcneill switch (depth) {
362c4d695ffSjmcneill case 32:
363c4d695ffSjmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE_32BPP,
364c4d695ffSjmcneill VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE);
365c4d695ffSjmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_COLOR_MATRIX_ARGB,
366c4d695ffSjmcneill VIU_OSD_BLK_CFG_W0_COLOR_MATRIX);
367c4d695ffSjmcneill break;
368c4d695ffSjmcneill case 24:
369c4d695ffSjmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE_24BPP,
370c4d695ffSjmcneill VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE);
371c4d695ffSjmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_COLOR_MATRIX_RGB,
372c4d695ffSjmcneill VIU_OSD_BLK_CFG_W0_COLOR_MATRIX);
373c4d695ffSjmcneill break;
374c4d695ffSjmcneill case 16:
375c4d695ffSjmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE_16BPP,
376c4d695ffSjmcneill VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE);
377c4d695ffSjmcneill w0 |= __SHIFTIN(VIU_OSD_BLK_CFG_W0_COLOR_MATRIX_RGB565,
378c4d695ffSjmcneill VIU_OSD_BLK_CFG_W0_COLOR_MATRIX);
379c4d695ffSjmcneill break;
380c4d695ffSjmcneill }
381c4d695ffSjmcneill w0 |= VIU_OSD_BLK_CFG_W0_LITTLE_ENDIAN;
382c4d695ffSjmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_RPT_Y;
383c4d695ffSjmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_INTERP_CTRL;
384c4d695ffSjmcneill if (interlace_p) {
385c4d695ffSjmcneill w0 |= VIU_OSD_BLK_CFG_W0_INTERLACE_EN;
386c4d695ffSjmcneill } else {
387c4d695ffSjmcneill w0 &= ~VIU_OSD_BLK_CFG_W0_INTERLACE_EN;
388c4d695ffSjmcneill }
389c4d695ffSjmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W0_REG, w0);
390c4d695ffSjmcneill
391c4d695ffSjmcneill w1 = __SHIFTIN(width - 1, VIU_OSD_BLK_CFG_W1_X_END) |
392c4d695ffSjmcneill __SHIFTIN(0, VIU_OSD_BLK_CFG_W1_X_START);
393c4d695ffSjmcneill w2 = __SHIFTIN(height - 1, VIU_OSD_BLK_CFG_W2_Y_END) |
394c4d695ffSjmcneill __SHIFTIN(0, VIU_OSD_BLK_CFG_W2_Y_START);
395c4d695ffSjmcneill w3 = __SHIFTIN(width - 1, VIU_OSD_BLK_CFG_W3_H_END) |
396c4d695ffSjmcneill __SHIFTIN(0, VIU_OSD_BLK_CFG_W3_H_START);
397c4d695ffSjmcneill w4 = __SHIFTIN(height - 1, VIU_OSD_BLK_CFG_W4_V_END) |
398c4d695ffSjmcneill __SHIFTIN(0, VIU_OSD_BLK_CFG_W4_V_START);
399c4d695ffSjmcneill
400c4d695ffSjmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W1_REG, w1);
401c4d695ffSjmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W2_REG, w2);
402c4d695ffSjmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W3_REG, w3);
403c4d695ffSjmcneill VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W4_REG, w4);
404c4d695ffSjmcneill }
405c4d695ffSjmcneill
406c4d695ffSjmcneill static void
meson_genfb_scaler_config(struct meson_genfb_softc * sc)407c4d695ffSjmcneill meson_genfb_scaler_config(struct meson_genfb_softc *sc)
408c4d695ffSjmcneill {
409c4d695ffSjmcneill prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev);
410c4d695ffSjmcneill uint32_t scctl, sci_wh, sco_h, sco_v, hsc, vsc, hps, vps, hip, vip;
411c4d695ffSjmcneill u_int width, height;
412c4d695ffSjmcneill bool interlace_p;
413c4d695ffSjmcneill
414c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "width", &width);
415c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "height", &height);
416c4d695ffSjmcneill prop_dictionary_get_bool(cfg, "interlace", &interlace_p);
417c4d695ffSjmcneill
418c4d695ffSjmcneill const u_int scale = sc->sc_scale;
419c4d695ffSjmcneill const u_int dst_w = (width * scale) / 100;
420c4d695ffSjmcneill const u_int dst_h = (height * scale) / 100;
421c4d695ffSjmcneill const u_int margin_w = (width - dst_w) / 2;
422c4d695ffSjmcneill const u_int margin_h = (height - dst_h) / 2;
423c4d695ffSjmcneill const bool scale_p = scale != 100;
424c4d695ffSjmcneill
425c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_SC_DUMMY_DATA_REG, 0x00808000);
426c4d695ffSjmcneill
427c4d695ffSjmcneill scctl = VPU_READ(sc, VPP_OSD_SC_CTRL0_REG);
428c4d695ffSjmcneill scctl |= VPP_OSD_SC_CTRL0_OSD_SC_PATH_EN;
429c4d695ffSjmcneill scctl &= ~VPP_OSD_SC_CTRL0_OSD_SC_SEL;
430c4d695ffSjmcneill scctl |= __SHIFTIN(1, VPP_OSD_SC_CTRL0_OSD_SC_SEL); /* OSD2 */
431c4d695ffSjmcneill scctl &= ~VPP_OSD_SC_CTRL0_DEFAULT_ALPHA;
432c4d695ffSjmcneill scctl |= __SHIFTIN(0, VPP_OSD_SC_CTRL0_DEFAULT_ALPHA);
433c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_SC_CTRL0_REG, scctl);
434c4d695ffSjmcneill
435c4d695ffSjmcneill sci_wh = __SHIFTIN(width - 1, VPP_OSD_SCI_WH_M1_WIDTH) |
436c4d695ffSjmcneill __SHIFTIN((height >> interlace_p) - 1, VPP_OSD_SCI_WH_M1_HEIGHT);
437c4d695ffSjmcneill sco_h = __SHIFTIN(margin_w, VPP_OSD_SCO_H_START) |
438c4d695ffSjmcneill __SHIFTIN(width - margin_w - 1, VPP_OSD_SCO_H_END);
439c4d695ffSjmcneill sco_v = __SHIFTIN(margin_h >> interlace_p, VPP_OSD_SCO_V_START) |
440c4d695ffSjmcneill __SHIFTIN(((height - margin_h) >> interlace_p) - 1,
441c4d695ffSjmcneill VPP_OSD_SCO_V_END);
442c4d695ffSjmcneill
443c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_SCI_WH_M1_REG, sci_wh);
444c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_SCO_H_REG, sco_h);
445c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_SCO_V_REG, sco_v);
446c4d695ffSjmcneill
447c4d695ffSjmcneill /* horizontal scaling */
448c4d695ffSjmcneill hsc = VPU_READ(sc, VPP_OSD_HSC_CTRL0_REG);
449c4d695ffSjmcneill if (scale_p) {
450c4d695ffSjmcneill hsc &= ~VPP_OSD_HSC_CTRL0_BANK_LENGTH;
451c4d695ffSjmcneill hsc |= __SHIFTIN(4, VPP_OSD_HSC_CTRL0_BANK_LENGTH);
452c4d695ffSjmcneill hsc &= ~VPP_OSD_HSC_CTRL0_INI_RCV_NUM0;
453c4d695ffSjmcneill hsc |= __SHIFTIN(4, VPP_OSD_HSC_CTRL0_INI_RCV_NUM0);
454c4d695ffSjmcneill hsc &= ~VPP_OSD_HSC_CTRL0_RPT_P0_NUM0;
455c4d695ffSjmcneill hsc |= __SHIFTIN(1, VPP_OSD_HSC_CTRL0_RPT_P0_NUM0);
456c4d695ffSjmcneill hsc |= VPP_OSD_HSC_CTRL0_HSCALE_EN;
457c4d695ffSjmcneill } else {
458c4d695ffSjmcneill hsc &= ~VPP_OSD_HSC_CTRL0_HSCALE_EN;
459c4d695ffSjmcneill }
460c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_HSC_CTRL0_REG, hsc);
461c4d695ffSjmcneill
462c4d695ffSjmcneill /* vertical scaling */
463c4d695ffSjmcneill vsc = VPU_READ(sc, VPP_OSD_VSC_CTRL0_REG);
464c4d695ffSjmcneill if (scale_p) {
465c4d695ffSjmcneill vsc &= ~VPP_OSD_VSC_CTRL0_BANK_LENGTH;
466c4d695ffSjmcneill vsc |= __SHIFTIN(4, VPP_OSD_VSC_CTRL0_BANK_LENGTH);
467c4d695ffSjmcneill vsc &= ~VPP_OSD_VSC_CTRL0_TOP_INI_RCV_NUM0;
468c4d695ffSjmcneill vsc |= __SHIFTIN(4, VPP_OSD_VSC_CTRL0_TOP_INI_RCV_NUM0);
469c4d695ffSjmcneill vsc &= ~VPP_OSD_VSC_CTRL0_TOP_RPT_P0_NUM0;
470c4d695ffSjmcneill vsc |= __SHIFTIN(1, VPP_OSD_VSC_CTRL0_TOP_RPT_P0_NUM0);
471c4d695ffSjmcneill vsc &= ~VPP_OSD_VSC_CTRL0_BOT_INI_RCV_NUM0;
472c4d695ffSjmcneill vsc &= ~VPP_OSD_VSC_CTRL0_BOT_RPT_P0_NUM0;
473c4d695ffSjmcneill vsc &= ~VPP_OSC_VSC_CTRL0_INTERLACE;
474c4d695ffSjmcneill if (interlace_p) {
475c4d695ffSjmcneill /* interlace */
476c4d695ffSjmcneill vsc |= VPP_OSC_VSC_CTRL0_INTERLACE;
477c4d695ffSjmcneill vsc |= __SHIFTIN(6, VPP_OSD_VSC_CTRL0_BOT_INI_RCV_NUM0);
478c4d695ffSjmcneill vsc |= __SHIFTIN(2, VPP_OSD_VSC_CTRL0_BOT_RPT_P0_NUM0);
479c4d695ffSjmcneill }
480c4d695ffSjmcneill vsc |= VPP_OSD_VSC_CTRL0_VSCALE_EN;
481c4d695ffSjmcneill } else {
482c4d695ffSjmcneill vsc &= ~VPP_OSD_VSC_CTRL0_VSCALE_EN;
483c4d695ffSjmcneill }
484c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_VSC_CTRL0_REG, vsc);
485c4d695ffSjmcneill
486c4d695ffSjmcneill /* free scale enable */
487c4d695ffSjmcneill if (scale_p) {
488c4d695ffSjmcneill const u_int hf_phase_step = ((width << 18) / dst_w) << 6;
489c4d695ffSjmcneill const u_int vf_phase_step = ((height << 20) / dst_h) << 4;
490c4d695ffSjmcneill const u_int bot_ini_phase =
491c4d695ffSjmcneill interlace_p ? ((vf_phase_step / 2) >> 8) : 0;
492c4d695ffSjmcneill
493c4d695ffSjmcneill hps = VPU_READ(sc, VPP_OSD_HSC_PHASE_STEP_REG);
494c4d695ffSjmcneill hps &= ~VPP_OSD_HSC_PHASE_STEP_FORMAT;
495c4d695ffSjmcneill hps |= __SHIFTIN(hf_phase_step, VPP_OSD_HSC_PHASE_STEP_FORMAT);
496c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_HSC_PHASE_STEP_REG, hps);
497c4d695ffSjmcneill
498c4d695ffSjmcneill hip = VPU_READ(sc, VPP_OSD_HSC_INI_PHASE_REG);
499c4d695ffSjmcneill hip &= ~VPP_OSD_HSC_INI_PHASE_1;
500c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_HSC_INI_PHASE_REG, hip);
501c4d695ffSjmcneill
502c4d695ffSjmcneill vps = VPU_READ(sc, VPP_OSD_VSC_PHASE_STEP_REG);
503c4d695ffSjmcneill vps &= ~VPP_OSD_VSC_PHASE_STEP_FORMAT;
504c4d695ffSjmcneill vps |= __SHIFTIN(hf_phase_step, VPP_OSD_VSC_PHASE_STEP_FORMAT);
505c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_VSC_PHASE_STEP_REG, vps);
506c4d695ffSjmcneill
507c4d695ffSjmcneill vip = VPU_READ(sc, VPP_OSD_VSC_INI_PHASE_REG);
508c4d695ffSjmcneill vip &= ~VPP_OSD_VSC_INI_PHASE_1;
509c4d695ffSjmcneill vip |= __SHIFTIN(0, VPP_OSD_VSC_INI_PHASE_1);
510c4d695ffSjmcneill vip &= ~VPP_OSD_VSC_INI_PHASE_0;
511c4d695ffSjmcneill vip |= __SHIFTIN(bot_ini_phase, VPP_OSD_VSC_INI_PHASE_0);
512c4d695ffSjmcneill VPU_WRITE(sc, VPP_OSD_VSC_INI_PHASE_REG, vip);
513c4d695ffSjmcneill }
514c4d695ffSjmcneill }
515c4d695ffSjmcneill
516c4d695ffSjmcneill static void
meson_genfb_init(struct meson_genfb_softc * sc)517c4d695ffSjmcneill meson_genfb_init(struct meson_genfb_softc *sc)
518c4d695ffSjmcneill {
519c4d695ffSjmcneill prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev);
520c4d695ffSjmcneill const struct sysctlnode *node, *devnode;
521c4d695ffSjmcneill u_int width = 0, height = 0, depth, flags, i, scale = 100;
522c4d695ffSjmcneill int error;
523c4d695ffSjmcneill
524c4d695ffSjmcneill /*
525c4d695ffSjmcneill * Firmware has (maybe) setup HDMI TX for us. Read the VIC from
526c4d695ffSjmcneill * the HDMI AVI InfoFrame (bits 6:0 in PB4) and map that to a
527c4d695ffSjmcneill * framebuffer geometry.
528c4d695ffSjmcneill */
529c4d695ffSjmcneill const uint32_t vic = HDMI_READ(sc, HDMITX_AVI_INFO_ADDR + 4) & 0x7f;
530c4d695ffSjmcneill for (i = 0; i < __arraycount(meson_genfb_modes); i++) {
531c4d695ffSjmcneill if (meson_genfb_modes[i].vic == vic) {
532c4d695ffSjmcneill aprint_debug(" [HDMI VIC %d]", vic);
533c4d695ffSjmcneill width = meson_genfb_modes[i].width;
534c4d695ffSjmcneill height = meson_genfb_modes[i].height;
535c4d695ffSjmcneill flags = meson_genfb_modes[i].flags;
536c4d695ffSjmcneill break;
537c4d695ffSjmcneill }
538c4d695ffSjmcneill }
539c4d695ffSjmcneill if (width == 0 || height == 0) {
540c4d695ffSjmcneill aprint_error(" [UNSUPPORTED HDMI VIC %d]", vic);
541c4d695ffSjmcneill return;
542c4d695ffSjmcneill }
543c4d695ffSjmcneill
544c4d695ffSjmcneill depth = AMLOGIC_GENFB_DEFAULT_DEPTH;
545c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "depth", &depth);
546c4d695ffSjmcneill switch (depth) {
547c4d695ffSjmcneill case 16:
548c4d695ffSjmcneill case 24:
549c4d695ffSjmcneill break;
550c4d695ffSjmcneill default:
551c4d695ffSjmcneill aprint_error_dev(sc->sc_gen.sc_dev,
552c4d695ffSjmcneill "unsupported depth %d, using %d\n", depth,
553c4d695ffSjmcneill AMLOGIC_GENFB_DEFAULT_DEPTH);
554c4d695ffSjmcneill depth = AMLOGIC_GENFB_DEFAULT_DEPTH;
555c4d695ffSjmcneill break;
556c4d695ffSjmcneill }
557c4d695ffSjmcneill prop_dictionary_set_uint8(cfg, "depth", depth);
558c4d695ffSjmcneill
559c4d695ffSjmcneill const uint32_t fbsize = width * height * (depth / 8);
560c4d695ffSjmcneill sc->sc_dmasize = (fbsize + 3) & ~3;
561c4d695ffSjmcneill
562c4d695ffSjmcneill error = meson_genfb_alloc_videomem(sc);
563c4d695ffSjmcneill if (error) {
564c4d695ffSjmcneill aprint_error_dev(sc->sc_gen.sc_dev,
565c4d695ffSjmcneill "failed to allocate %u bytes of video memory: %d\n",
566c4d695ffSjmcneill (u_int)sc->sc_dmasize, error);
567c4d695ffSjmcneill return;
568c4d695ffSjmcneill }
569c4d695ffSjmcneill
570c4d695ffSjmcneill prop_dictionary_get_uint32(cfg, "scale", &scale);
571c4d695ffSjmcneill if (scale > 100) {
572c4d695ffSjmcneill scale = 100;
573c4d695ffSjmcneill } else if (scale < 10) {
574c4d695ffSjmcneill scale = 10;
575c4d695ffSjmcneill }
576c4d695ffSjmcneill sc->sc_scale = scale;
577c4d695ffSjmcneill
578c4d695ffSjmcneill prop_dictionary_set_uint32(cfg, "width", width);
579c4d695ffSjmcneill prop_dictionary_set_uint32(cfg, "height", height);
580c4d695ffSjmcneill prop_dictionary_set_bool(cfg, "dblscan", !!(flags & DBLSCAN));
581c4d695ffSjmcneill prop_dictionary_set_bool(cfg, "interlace", !!(flags & INTERLACE));
582c4d695ffSjmcneill prop_dictionary_set_uint16(cfg, "linebytes", width * (depth / 8));
583c4d695ffSjmcneill prop_dictionary_set_uint32(cfg, "address", 0);
584c4d695ffSjmcneill prop_dictionary_set_uint32(cfg, "virtual_address",
585c4d695ffSjmcneill (uintptr_t)sc->sc_dmap);
586c4d695ffSjmcneill
587c4d695ffSjmcneill meson_genfb_canvas_config(sc);
588c4d695ffSjmcneill meson_genfb_osd_config(sc);
589c4d695ffSjmcneill meson_genfb_scaler_config(sc);
590c4d695ffSjmcneill
591c4d695ffSjmcneill /* sysctl setup */
592c4d695ffSjmcneill error = sysctl_createv(&sc->sc_sysctllog, 0, NULL, &node,
593c4d695ffSjmcneill CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
594c4d695ffSjmcneill NULL, 0, NULL, 0, CTL_HW, CTL_EOL);
595c4d695ffSjmcneill if (error)
596c4d695ffSjmcneill goto sysctl_failed;
597c4d695ffSjmcneill error = sysctl_createv(&sc->sc_sysctllog, 0, &node, &devnode,
598c4d695ffSjmcneill 0, CTLTYPE_NODE, device_xname(sc->sc_gen.sc_dev), NULL,
599c4d695ffSjmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
600c4d695ffSjmcneill if (error)
601c4d695ffSjmcneill goto sysctl_failed;
602c4d695ffSjmcneill error = sysctl_createv(&sc->sc_sysctllog, 0, &devnode, &node,
603c4d695ffSjmcneill CTLFLAG_READWRITE, CTLTYPE_INT, "scale", NULL,
604c4d695ffSjmcneill meson_genfb_scale_helper, 0, (void *)sc, 0,
605c4d695ffSjmcneill CTL_CREATE, CTL_EOL);
606c4d695ffSjmcneill if (error)
607c4d695ffSjmcneill goto sysctl_failed;
608c4d695ffSjmcneill sc->sc_node_scale = node->sysctl_num;
609c4d695ffSjmcneill
610c4d695ffSjmcneill return;
611c4d695ffSjmcneill
612c4d695ffSjmcneill sysctl_failed:
613c4d695ffSjmcneill aprint_error_dev(sc->sc_gen.sc_dev,
614c4d695ffSjmcneill "couldn't create sysctl nodes (%d)\n", error);
615c4d695ffSjmcneill sysctl_teardown(&sc->sc_sysctllog);
616c4d695ffSjmcneill }
617c4d695ffSjmcneill
618c4d695ffSjmcneill static int
meson_genfb_scale_helper(SYSCTLFN_ARGS)619c4d695ffSjmcneill meson_genfb_scale_helper(SYSCTLFN_ARGS)
620c4d695ffSjmcneill {
621c4d695ffSjmcneill struct meson_genfb_softc *sc;
622c4d695ffSjmcneill struct sysctlnode node;
623c4d695ffSjmcneill int scale, oldscale, error;
624c4d695ffSjmcneill
625c4d695ffSjmcneill node = *rnode;
626c4d695ffSjmcneill sc = node.sysctl_data;
627c4d695ffSjmcneill scale = oldscale = sc->sc_scale;
628c4d695ffSjmcneill node.sysctl_data = &scale;
629c4d695ffSjmcneill error = sysctl_lookup(SYSCTLFN_CALL(&node));
630c4d695ffSjmcneill if (error || newp == NULL)
631c4d695ffSjmcneill return error;
632c4d695ffSjmcneill
633c4d695ffSjmcneill if (scale > 100) {
634c4d695ffSjmcneill scale = 100;
635c4d695ffSjmcneill } else if (scale < 10) {
636c4d695ffSjmcneill scale = 10;
637c4d695ffSjmcneill }
638c4d695ffSjmcneill
639c4d695ffSjmcneill if (scale == oldscale) {
640c4d695ffSjmcneill return 0;
641c4d695ffSjmcneill }
642c4d695ffSjmcneill
643c4d695ffSjmcneill mutex_enter(&sc->sc_lock);
644c4d695ffSjmcneill sc->sc_scale = scale;
645c4d695ffSjmcneill meson_genfb_scaler_config(sc);
646c4d695ffSjmcneill mutex_exit(&sc->sc_lock);
647c4d695ffSjmcneill
648c4d695ffSjmcneill return 0;
649c4d695ffSjmcneill }
650c4d695ffSjmcneill
651c4d695ffSjmcneill static int
meson_genfb_alloc_videomem(struct meson_genfb_softc * sc)652c4d695ffSjmcneill meson_genfb_alloc_videomem(struct meson_genfb_softc *sc)
653c4d695ffSjmcneill {
654c4d695ffSjmcneill int error, nsegs;
655c4d695ffSjmcneill
656c4d695ffSjmcneill error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmasize, 0x1000, 0,
657c4d695ffSjmcneill sc->sc_dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
658c4d695ffSjmcneill if (error)
659c4d695ffSjmcneill return error;
660c4d695ffSjmcneill error = bus_dmamem_map(sc->sc_dmat, sc->sc_dmasegs, nsegs,
661c4d695ffSjmcneill sc->sc_dmasize, &sc->sc_dmap, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
662c4d695ffSjmcneill if (error)
663c4d695ffSjmcneill goto free;
664c4d695ffSjmcneill error = bus_dmamap_create(sc->sc_dmat, sc->sc_dmasize, 1,
665c4d695ffSjmcneill sc->sc_dmasize, 0, BUS_DMA_WAITOK, &sc->sc_dmamap);
666c4d695ffSjmcneill if (error)
667c4d695ffSjmcneill goto unmap;
668c4d695ffSjmcneill error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmap,
669c4d695ffSjmcneill sc->sc_dmasize, NULL, BUS_DMA_WAITOK);
670c4d695ffSjmcneill if (error)
671c4d695ffSjmcneill goto destroy;
672c4d695ffSjmcneill
673c4d695ffSjmcneill memset(sc->sc_dmap, 0, sc->sc_dmasize);
674c4d695ffSjmcneill
675c4d695ffSjmcneill return 0;
676c4d695ffSjmcneill
677c4d695ffSjmcneill destroy:
678c4d695ffSjmcneill bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
679c4d695ffSjmcneill unmap:
680c4d695ffSjmcneill bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmap, sc->sc_dmasize);
681c4d695ffSjmcneill free:
682c4d695ffSjmcneill bus_dmamem_free(sc->sc_dmat, sc->sc_dmasegs, nsegs);
683c4d695ffSjmcneill
684c4d695ffSjmcneill sc->sc_dmasize = 0;
685c4d695ffSjmcneill sc->sc_dmap = NULL;
686c4d695ffSjmcneill
687c4d695ffSjmcneill return error;
688c4d695ffSjmcneill }
689c4d695ffSjmcneill
690c4d695ffSjmcneill void
meson_genfb_set_console_dev(device_t dev)691c4d695ffSjmcneill meson_genfb_set_console_dev(device_t dev)
692c4d695ffSjmcneill {
693c4d695ffSjmcneill KASSERT(meson_genfb_console_dev == NULL);
694c4d695ffSjmcneill meson_genfb_console_dev = dev;
695c4d695ffSjmcneill }
696c4d695ffSjmcneill
697c4d695ffSjmcneill void
meson_genfb_ddb_trap_callback(int where)698c4d695ffSjmcneill meson_genfb_ddb_trap_callback(int where)
699c4d695ffSjmcneill {
700c4d695ffSjmcneill if (meson_genfb_console_dev == NULL)
701c4d695ffSjmcneill return;
702c4d695ffSjmcneill
703c4d695ffSjmcneill if (where) {
704c4d695ffSjmcneill genfb_enable_polling(meson_genfb_console_dev);
705c4d695ffSjmcneill } else {
706c4d695ffSjmcneill genfb_disable_polling(meson_genfb_console_dev);
707c4d695ffSjmcneill }
708c4d695ffSjmcneill }
709c4d695ffSjmcneill
710c4d695ffSjmcneill static int
meson_genfb_console_match(int phandle)711c4d695ffSjmcneill meson_genfb_console_match(int phandle)
712c4d695ffSjmcneill {
713*8e90f9edSthorpej return of_compatible_match(phandle, compat_data);
714c4d695ffSjmcneill }
715c4d695ffSjmcneill
716c4d695ffSjmcneill static void
meson_genfb_console_consinit(struct fdt_attach_args * faa,u_int uart_freq)717c4d695ffSjmcneill meson_genfb_console_consinit(struct fdt_attach_args *faa, u_int uart_freq)
718c4d695ffSjmcneill {
719c4d695ffSjmcneill meson_genfb_console_phandle = faa->faa_phandle;
720c4d695ffSjmcneill genfb_cnattach();
721c4d695ffSjmcneill }
722c4d695ffSjmcneill
723c4d695ffSjmcneill static const struct fdt_console meson_genfb_fdt_console = {
724c4d695ffSjmcneill .match = meson_genfb_console_match,
725c4d695ffSjmcneill .consinit = meson_genfb_console_consinit,
726c4d695ffSjmcneill };
727c4d695ffSjmcneill
728c4d695ffSjmcneill FDT_CONSOLE(meson_genfb, &meson_genfb_fdt_console);
729