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