exynos5_fimd.c revision 266341
1223637Sbz/*-
2126353Smlaier * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3126353Smlaier * All rights reserved.
4126353Smlaier *
5130617Smlaier * Redistribution and use in source and binary forms, with or without
6126353Smlaier * modification, are permitted provided that the following conditions
7126353Smlaier * are met:
8126353Smlaier * 1. Redistributions of source code must retain the above copyright
9126353Smlaier *    notice, this list of conditions and the following disclaimer.
10126353Smlaier * 2. Redistributions in binary form must reproduce the above copyright
11126353Smlaier *    notice, this list of conditions and the following disclaimer in the
12126353Smlaier *    documentation and/or other materials provided with the distribution.
13126353Smlaier *
14126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15126353Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16126353Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17126353Smlaier * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18126353Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19126353Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20126353Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21126353Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22126353Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23126353Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24126353Smlaier * SUCH DAMAGE.
25126353Smlaier */
26126353Smlaier
27126353Smlaier/*
28126353Smlaier * Samsung Exynos 5 Display Controller
29126353Smlaier * Chapter 15, Exynos 5 Dual User's Manual Public Rev 1.00
30126353Smlaier */
31126353Smlaier
32126353Smlaier#include <sys/cdefs.h>
33126353Smlaier__FBSDID("$FreeBSD: stable/10/sys/arm/samsung/exynos/exynos5_fimd.c 266341 2014-05-17 19:37:04Z ian $");
34127082Sobrien
35127082Sobrien#include <sys/param.h>
36127082Sobrien#include <sys/systm.h>
37126353Smlaier#include <sys/bus.h>
38126353Smlaier#include <sys/kernel.h>
39126353Smlaier#include <sys/module.h>
40145840Smlaier#include <sys/malloc.h>
41126353Smlaier#include <sys/rman.h>
42223637Sbz#include <sys/timeet.h>
43223637Sbz#include <sys/timetc.h>
44223637Sbz#include <sys/watchdog.h>
45223637Sbz#include <sys/fbio.h>
46126353Smlaier#include <sys/consio.h>
47126353Smlaier#include <sys/eventhandler.h>
48126353Smlaier#include <sys/gpio.h>
49126353Smlaier
50126353Smlaier#include <vm/vm.h>
51171172Smlaier#include <vm/vm_extern.h>
52126353Smlaier#include <vm/vm_kern.h>
53126353Smlaier
54126353Smlaier#include <dev/fdt/fdt_common.h>
55126353Smlaier#include <dev/ofw/openfirm.h>
56126353Smlaier#include <dev/ofw/ofw_bus.h>
57126353Smlaier#include <dev/ofw/ofw_bus_subr.h>
58126353Smlaier
59126353Smlaier#include <dev/vt/vt.h>
60126353Smlaier#include <dev/vt/colors/vt_termcolors.h>
61126353Smlaier
62126353Smlaier#include <arm/samsung/exynos/exynos5_common.h>
63126353Smlaier
64126353Smlaier#include "gpio_if.h"
65126353Smlaier
66126353Smlaier#include <machine/bus.h>
67126353Smlaier#include <machine/fdt.h>
68126353Smlaier#include <machine/cpu.h>
69126353Smlaier#include <machine/intr.h>
70145840Smlaier
71145840Smlaier#include "fb_if.h"
72145840Smlaier
73126353Smlaier#define	FIMDBYPASS_DISP1	(1 << 15)
74130617Smlaier
75130617Smlaier#define	VIDCON0		(0x0)
76171172Smlaier#define	VIDCON0_ENVID	(1 << 1)
77171172Smlaier#define	VIDCON0_ENVID_F	(1 << 0)
78223637Sbz#define	CLKVAL_F	0xb
79223637Sbz#define	CLKVAL_F_OFFSET	6
80223637Sbz
81145840Smlaier#define	WINCON0		0x0020
82145840Smlaier#define	WINCON1		0x0024
83145840Smlaier#define	WINCON2		0x0028
84145840Smlaier#define	WINCON3		0x002C
85145840Smlaier#define	WINCON4		0x0030
86145840Smlaier
87145840Smlaier#define	ENLOCAL_F			(1 << 22)
88126353Smlaier#define	BPPMODE_F_RGB_16BIT_565		0x5
89145840Smlaier#define	BPPMODE_F_OFFSET		2
90126353Smlaier#define	ENWIN_F_ENABLE			(1 << 0)
91171172Smlaier#define	HALF_WORD_SWAP_EN		(1 << 16)
92145840Smlaier
93130617Smlaier#define	SHADOWCON	0x0034
94130617Smlaier#define	CHANNEL0_EN	(1 << 0)
95130617Smlaier
96130617Smlaier#define	VIDOSD0A	0x0040
97130617Smlaier#define	VIDOSD0B	0x0044
98145840Smlaier#define	VIDOSD0C	0x0048
99126353Smlaier
100126353Smlaier#define	VIDW00ADD0B0	0x00A0
101171172Smlaier#define	VIDW00ADD0B1	0x00A4
102171172Smlaier#define	VIDW00ADD0B2	0x20A0
103171172Smlaier#define	VIDW00ADD1B0	0x00D0
104171172Smlaier#define	VIDW00ADD1B1	0x00D4
105126353Smlaier#define	VIDW00ADD1B2	0x20D0
106126353Smlaier
107171172Smlaier#define	VIDW00ADD2	0x0100
108171172Smlaier#define	VIDW01ADD2	0x0104
109171172Smlaier#define	VIDW02ADD2	0x0108
110126353Smlaier#define	VIDW03ADD2	0x010C
111126353Smlaier#define	VIDW04ADD2	0x0110
112126353Smlaier
113126353Smlaier#define	VIDCON1		(0x04)
114126353Smlaier#define	VIDTCON0	0x0010
115171172Smlaier#define	VIDTCON1	0x0014
116130617Smlaier#define	VIDTCON2	0x0018
117130617Smlaier#define	VIDTCON3	0x001C
118126353Smlaier
119126353Smlaier#define	VIDINTCON0	0x0130
120171172Smlaier#define	VIDINTCON1	0x0134
121171172Smlaier
122126353Smlaier#define	VSYNC_PULSE_WIDTH_VAL		0x3
123126353Smlaier#define	VSYNC_PULSE_WIDTH_OFFSET	0
124126353Smlaier#define	V_FRONT_PORCH_VAL		0x3
125126353Smlaier#define	V_FRONT_PORCH_OFFSET		8
126126353Smlaier#define	V_BACK_PORCH_VAL		0x3
127126353Smlaier#define	V_BACK_PORCH_OFFSET		16
128130617Smlaier
129130617Smlaier#define	HSYNC_PULSE_WIDTH_VAL		0x3
130126353Smlaier#define	HSYNC_PULSE_WIDTH_OFFSET	0
131171172Smlaier#define	H_FRONT_PORCH_VAL		0x3
132171172Smlaier#define	H_FRONT_PORCH_OFFSET		8
133171172Smlaier#define	H_BACK_PORCH_VAL		0x3
134171172Smlaier#define	H_BACK_PORCH_OFFSET		16
135171172Smlaier
136171172Smlaier#define	HOZVAL_OFFSET		0
137171172Smlaier#define	LINEVAL_OFFSET		11
138171172Smlaier
139171172Smlaier#define	OSD_RIGHTBOTX_F_OFFSET		11
140126353Smlaier#define	OSD_RIGHTBOTY_F_OFFSET		0
141126353Smlaier
142126353Smlaier#define	DPCLKCON	0x27c
143126353Smlaier#define	DPCLKCON_EN	(1 << 1)
144171172Smlaier
145171172Smlaier#define	DREAD4(_sc, _reg)         \
146171172Smlaier	bus_space_read_4(_sc->bst_disp, _sc->bsh_disp, _reg)
147171172Smlaier#define	DWRITE4(_sc, _reg, _val)  \
148171172Smlaier	bus_space_write_4(_sc->bst_disp, _sc->bsh_disp, _reg, _val)
149171172Smlaier
150126353Smlaierstruct panel_info {
151126353Smlaier	uint32_t	width;
152126353Smlaier	uint32_t	height;
153126353Smlaier	uint32_t	h_back_porch;
154126353Smlaier	uint32_t	h_pulse_width;
155126353Smlaier	uint32_t	h_front_porch;
156126353Smlaier	uint32_t	v_back_porch;
157126353Smlaier	uint32_t	v_pulse_width;
158126353Smlaier	uint32_t	v_front_porch;
159126353Smlaier	uint32_t	clk_div;
160126353Smlaier	uint32_t	backlight_pin;
161126353Smlaier	uint32_t	fixvclk;
162126353Smlaier	uint32_t	ivclk;
163145840Smlaier	uint32_t	clkval_f;
164126353Smlaier};
165126353Smlaier
166126353Smlaierstruct fimd_softc {
167126353Smlaier	struct resource		*res[3];
168126353Smlaier	bus_space_tag_t		bst;
169126353Smlaier	bus_space_handle_t	bsh;
170126353Smlaier	bus_space_tag_t		bst_disp;
171126353Smlaier	bus_space_handle_t	bsh_disp;
172126353Smlaier	bus_space_tag_t		bst_sysreg;
173145840Smlaier	bus_space_handle_t	bsh_sysreg;
174126353Smlaier
175126353Smlaier	void			*ih;
176126353Smlaier	device_t		dev;
177126353Smlaier	device_t		sc_fbd;		/* fbd child */
178126353Smlaier	struct fb_info		sc_info;
179126353Smlaier	struct panel_info	*panel;
180126353Smlaier};
181126353Smlaier
182126353Smlaierstatic struct resource_spec fimd_spec[] = {
183145840Smlaier	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Timer registers */
184126353Smlaier	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* FIMD */
185126353Smlaier	{ SYS_RES_MEMORY,	2,	RF_ACTIVE },	/* DISP */
186126353Smlaier	{ -1, 0 }
187126353Smlaier};
188126353Smlaier
189126353Smlaierstatic int
190126353Smlaierfimd_probe(device_t dev)
191126353Smlaier{
192126353Smlaier
193145840Smlaier	if (!ofw_bus_status_okay(dev))
194126353Smlaier		return (ENXIO);
195126353Smlaier
196126353Smlaier	if (!ofw_bus_is_compatible(dev, "exynos,fimd"))
197126353Smlaier		return (ENXIO);
198126353Smlaier
199126353Smlaier	device_set_desc(dev, "Samsung Exynos 5 Display Controller");
200126353Smlaier	return (BUS_PROBE_DEFAULT);
201126353Smlaier}
202126353Smlaier
203126353Smlaierstatic int
204126353Smlaierget_panel_info(struct fimd_softc *sc, struct panel_info *panel)
205126353Smlaier{
206126353Smlaier	phandle_t node;
207126353Smlaier	pcell_t dts_value[3];
208126353Smlaier	int len;
209126353Smlaier
210130617Smlaier	if ((node = ofw_bus_get_node(sc->dev)) == -1)
211223637Sbz		return (ENXIO);
212126353Smlaier
213126353Smlaier	/* panel size */
214126353Smlaier	if ((len = OF_getproplen(node, "panel-size")) <= 0)
215223637Sbz		return (ENXIO);
216130617Smlaier	OF_getprop(node, "panel-size", &dts_value, len);
217130617Smlaier	panel->width = fdt32_to_cpu(dts_value[0]);
218126353Smlaier	panel->height = fdt32_to_cpu(dts_value[1]);
219126353Smlaier
220126353Smlaier	/* hsync */
221126353Smlaier	if ((len = OF_getproplen(node, "panel-hsync")) <= 0)
222171172Smlaier		return (ENXIO);
223126353Smlaier	OF_getprop(node, "panel-hsync", &dts_value, len);
224126353Smlaier	panel->h_back_porch = fdt32_to_cpu(dts_value[0]);
225126353Smlaier	panel->h_pulse_width = fdt32_to_cpu(dts_value[1]);
226126353Smlaier	panel->h_front_porch = fdt32_to_cpu(dts_value[2]);
227126353Smlaier
228126353Smlaier	/* vsync */
229171172Smlaier	if ((len = OF_getproplen(node, "panel-vsync")) <= 0)
230223637Sbz		return (ENXIO);
231171172Smlaier	OF_getprop(node, "panel-vsync", &dts_value, len);
232126353Smlaier	panel->v_back_porch = fdt32_to_cpu(dts_value[0]);
233126353Smlaier	panel->v_pulse_width = fdt32_to_cpu(dts_value[1]);
234126353Smlaier	panel->v_front_porch = fdt32_to_cpu(dts_value[2]);
235126353Smlaier
236126353Smlaier	/* clk divider */
237126353Smlaier	if ((len = OF_getproplen(node, "panel-clk-div")) <= 0)
238223057Sbz		return (ENXIO);
239145840Smlaier	OF_getprop(node, "panel-clk-div", &dts_value, len);
240223637Sbz	panel->clk_div = fdt32_to_cpu(dts_value[0]);
241223637Sbz
242223637Sbz	/* backlight pin */
243223637Sbz	if ((len = OF_getproplen(node, "panel-backlight-pin")) <= 0)
244223637Sbz		return (ENXIO);
245126353Smlaier	OF_getprop(node, "panel-backlight-pin", &dts_value, len);
246126353Smlaier	panel->backlight_pin = fdt32_to_cpu(dts_value[0]);
247126353Smlaier
248126353Smlaier	return (0);
249126353Smlaier}
250126353Smlaier
251126353Smlaierstatic int
252126353Smlaierfimd_init(struct fimd_softc *sc)
253126353Smlaier{
254127024Smlaier	struct panel_info *panel;
255126355Smlaier	int reg;
256126355Smlaier
257126355Smlaier	panel = sc->panel;
258126353Smlaier
259126353Smlaier	/* fb_init */
260126353Smlaier	reg = panel->ivclk | panel->fixvclk;
261126353Smlaier	DWRITE4(sc,VIDCON1,reg);
262126353Smlaier
263126353Smlaier	reg = (VIDCON0_ENVID | VIDCON0_ENVID_F);
264126353Smlaier	reg |= (panel->clkval_f << CLKVAL_F_OFFSET);
265126353Smlaier	WRITE4(sc,VIDCON0,reg);
266126353Smlaier
267126353Smlaier	reg = (panel->v_pulse_width << VSYNC_PULSE_WIDTH_OFFSET);
268126353Smlaier	reg |= (panel->v_front_porch << V_FRONT_PORCH_OFFSET);
269126353Smlaier	reg |= (panel->v_back_porch << V_BACK_PORCH_OFFSET);
270126353Smlaier	DWRITE4(sc,VIDTCON0,reg);
271126353Smlaier
272126353Smlaier	reg = (panel->h_pulse_width << HSYNC_PULSE_WIDTH_OFFSET);
273126353Smlaier	reg |= (panel->h_front_porch << H_FRONT_PORCH_OFFSET);
274126353Smlaier	reg |= (panel->h_back_porch << H_BACK_PORCH_OFFSET);
275126353Smlaier	DWRITE4(sc,VIDTCON1,reg);
276126353Smlaier
277126353Smlaier	reg = ((panel->width - 1) << HOZVAL_OFFSET);
278126353Smlaier	reg |= ((panel->height - 1) << LINEVAL_OFFSET);
279126353Smlaier	DWRITE4(sc,VIDTCON2,reg);
280126353Smlaier
281126353Smlaier	WRITE4(sc,VIDW00ADD0B0, sc->sc_info.fb_pbase);
282126353Smlaier	WRITE4(sc,VIDW00ADD1B0, sc->sc_info.fb_pbase + sc->sc_info.fb_size);
283126353Smlaier	WRITE4(sc,VIDW00ADD2, panel->width * 2);
284126353Smlaier
285126353Smlaier	reg = ((panel->width - 1) << OSD_RIGHTBOTX_F_OFFSET);
286126353Smlaier	reg |= ((panel->height - 1) << OSD_RIGHTBOTY_F_OFFSET);
287126353Smlaier	WRITE4(sc,VIDOSD0B,reg);
288126353Smlaier
289126353Smlaier	reg = panel->width * panel->height;
290126353Smlaier	WRITE4(sc,VIDOSD0C,reg);
291126353Smlaier
292126353Smlaier	reg = READ4(sc, SHADOWCON);
293126353Smlaier	reg |= CHANNEL0_EN;
294126353Smlaier	reg &= ~(1 << 5); /* disable local path for channel0 */
295126353Smlaier	WRITE4(sc,SHADOWCON,reg);
296126353Smlaier
297126353Smlaier	reg = BPPMODE_F_RGB_16BIT_565 << BPPMODE_F_OFFSET;
298126353Smlaier	reg |= ENWIN_F_ENABLE | HALF_WORD_SWAP_EN; /* Note: swap=0 when ENLOCAL==1 */
299126353Smlaier	reg &= ~ENLOCAL_F; /* use DMA */
300126353Smlaier	WRITE4(sc,WINCON0,reg);
301145840Smlaier
302126353Smlaier	/* Enable DisplayPort Clk */
303145840Smlaier	WRITE4(sc, DPCLKCON, DPCLKCON_EN);
304126353Smlaier
305145840Smlaier	return (0);
306145840Smlaier}
307171172Smlaier
308126353Smlaierstatic int
309145840Smlaierfimd_attach(device_t dev)
310145840Smlaier{
311126353Smlaier	struct panel_info panel;
312145840Smlaier	struct fimd_softc *sc;
313126353Smlaier	device_t gpio_dev;
314145840Smlaier	int reg;
315145840Smlaier
316145840Smlaier	sc = device_get_softc(dev);
317145840Smlaier	sc->dev = dev;
318145840Smlaier
319145840Smlaier	if (bus_alloc_resources(dev, fimd_spec, sc->res)) {
320145840Smlaier		device_printf(dev, "could not allocate resources\n");
321145840Smlaier		return (ENXIO);
322130617Smlaier	}
323130617Smlaier
324145840Smlaier	/* Memory interface */
325145840Smlaier	sc->bst = rman_get_bustag(sc->res[0]);
326130617Smlaier	sc->bsh = rman_get_bushandle(sc->res[0]);
327130617Smlaier	sc->bst_disp = rman_get_bustag(sc->res[1]);
328130617Smlaier	sc->bsh_disp = rman_get_bushandle(sc->res[1]);
329126353Smlaier	sc->bst_sysreg = rman_get_bustag(sc->res[2]);
330126353Smlaier	sc->bsh_sysreg = rman_get_bushandle(sc->res[2]);
331126353Smlaier
332126353Smlaier	if (get_panel_info(sc, &panel)) {
333126353Smlaier		device_printf(dev, "Can't get panel info\n");
334126353Smlaier		return (ENXIO);
335145840Smlaier	}
336126353Smlaier
337130617Smlaier	panel.fixvclk = 0;
338126353Smlaier	panel.ivclk = 0;
339130617Smlaier	panel.clkval_f = 2;
340130617Smlaier
341145840Smlaier	sc->panel = &panel;
342145840Smlaier
343145840Smlaier	/* Get the GPIO device, we need this to give power to USB */
344130617Smlaier	gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
345130617Smlaier	if (gpio_dev == NULL) {
346130617Smlaier		/* TODO */
347126353Smlaier	}
348126353Smlaier
349126353Smlaier	reg = bus_space_read_4(sc->bst_sysreg, sc->bsh_sysreg, 0x214);
350126353Smlaier	reg |= FIMDBYPASS_DISP1;
351126353Smlaier	bus_space_write_4(sc->bst_sysreg, sc->bsh_sysreg, 0x214, reg);
352126353Smlaier
353126353Smlaier	sc->sc_info.fb_width = panel.width;
354126353Smlaier	sc->sc_info.fb_height = panel.height;
355130617Smlaier	sc->sc_info.fb_stride = sc->sc_info.fb_width * 2;
356126353Smlaier	sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 16;
357126353Smlaier	sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride;
358126353Smlaier	sc->sc_info.fb_vbase = (intptr_t)kmem_alloc_contig(kernel_arena,
359130617Smlaier	    sc->sc_info.fb_size, M_ZERO, 0, ~0, PAGE_SIZE, 0, VM_MEMATTR_UNCACHEABLE);
360130617Smlaier	sc->sc_info.fb_pbase = (intptr_t)vtophys(sc->sc_info.fb_vbase);
361145840Smlaier
362130617Smlaier#if 0
363130617Smlaier	printf("%dx%d [%d]\n", sc->sc_info.fb_width, sc->sc_info.fb_height,
364130617Smlaier	    sc->sc_info.fb_stride);
365126353Smlaier	printf("pbase == 0x%08x\n", sc->sc_info.fb_pbase);
366126353Smlaier#endif
367126353Smlaier
368126353Smlaier	memset((int8_t *)sc->sc_info.fb_vbase, 0x0, sc->sc_info.fb_size);
369126353Smlaier
370126353Smlaier	fimd_init(sc);
371130617Smlaier
372126353Smlaier	sc->sc_info.fb_name = device_get_nameunit(dev);
373130617Smlaier
374130617Smlaier	/* Ask newbus to attach framebuffer device to me. */
375130617Smlaier	sc->sc_fbd = device_add_child(dev, "fbd", device_get_unit(dev));
376130617Smlaier	if (sc->sc_fbd == NULL)
377130617Smlaier		device_printf(dev, "Can't attach fbd device\n");
378130617Smlaier
379130617Smlaier	if (device_probe_and_attach(sc->sc_fbd) != 0) {
380130617Smlaier		device_printf(sc->dev, "Failed to attach fbd device\n");
381130617Smlaier	}
382130617Smlaier
383130617Smlaier	return (0);
384130617Smlaier}
385130617Smlaier
386130617Smlaierstatic struct fb_info *
387130617Smlaierfimd_fb_getinfo(device_t dev)
388130617Smlaier{
389130617Smlaier	struct fimd_softc *sc = device_get_softc(dev);
390130617Smlaier
391126353Smlaier	return (&sc->sc_info);
392126353Smlaier}
393223637Sbz
394126353Smlaierstatic device_method_t fimd_methods[] = {
395126353Smlaier	DEVMETHOD(device_probe,		fimd_probe),
396126353Smlaier	DEVMETHOD(device_attach,	fimd_attach),
397171172Smlaier
398171172Smlaier	/* Framebuffer service methods */
399171172Smlaier	DEVMETHOD(fb_getinfo,		fimd_fb_getinfo),
400171172Smlaier	{ 0, 0 }
401171172Smlaier};
402171172Smlaier
403171172Smlaierstatic driver_t fimd_driver = {
404171172Smlaier	"fb",
405171172Smlaier	fimd_methods,
406171172Smlaier	sizeof(struct fimd_softc),
407171172Smlaier};
408171172Smlaier
409171172Smlaierstatic devclass_t fimd_devclass;
410171172Smlaier
411171172SmlaierDRIVER_MODULE(fb, simplebus, fimd_driver, fimd_devclass, 0, 0);
412171172Smlaier