vf_dcu4.c (266155) | vf_dcu4.c (266274) |
---|---|
1/*- 2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 16 unchanged lines hidden (view full) --- 25 */ 26 27/* 28 * Vybrid Family Display Control Unit (DCU4) 29 * Chapter 55, Vybrid Reference Manual, Rev. 5, 07/2013 30 */ 31 32#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 16 unchanged lines hidden (view full) --- 25 */ 26 27/* 28 * Vybrid Family Display Control Unit (DCU4) 29 * Chapter 55, Vybrid Reference Manual, Rev. 5, 07/2013 30 */ 31 32#include <sys/cdefs.h> |
33__FBSDID("$FreeBSD: stable/10/sys/arm/freescale/vybrid/vf_dcu4.c 266155 2014-05-15 16:23:24Z ian $"); | 33__FBSDID("$FreeBSD: stable/10/sys/arm/freescale/vybrid/vf_dcu4.c 266274 2014-05-16 23:27:18Z ian $"); |
34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/malloc.h> 41#include <sys/rman.h> 42#include <sys/timeet.h> 43#include <sys/timetc.h> 44#include <sys/watchdog.h> 45#include <sys/fbio.h> 46#include <sys/consio.h> 47#include <sys/eventhandler.h> | 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/malloc.h> 41#include <sys/rman.h> 42#include <sys/timeet.h> 43#include <sys/timetc.h> 44#include <sys/watchdog.h> 45#include <sys/fbio.h> 46#include <sys/consio.h> 47#include <sys/eventhandler.h> |
48#include <sys/gpio.h> |
|
48 49#include <dev/fdt/fdt_common.h> 50#include <dev/ofw/openfirm.h> 51#include <dev/ofw/ofw_bus.h> 52#include <dev/ofw/ofw_bus_subr.h> 53 54#include <dev/vt/vt.h> 55#include <dev/vt/colors/vt_termcolors.h> 56 | 49 50#include <dev/fdt/fdt_common.h> 51#include <dev/ofw/openfirm.h> 52#include <dev/ofw/ofw_bus.h> 53#include <dev/ofw/ofw_bus_subr.h> 54 55#include <dev/vt/vt.h> 56#include <dev/vt/colors/vt_termcolors.h> 57 |
58#include "gpio_if.h" 59 |
|
57#include <machine/bus.h> 58#include <machine/fdt.h> 59#include <machine/cpu.h> 60#include <machine/intr.h> 61 62#include "fb_if.h" 63 64#include <arm/freescale/vybrid/vf_common.h> --- 4 unchanged lines hidden (view full) --- 69#define DCU_CTRLDESCCURSOR4 0x00C /* Control Descriptor Cursor 4 */ 70#define DCU_DCU_MODE 0x010 /* DCU4 Mode */ 71#define DCU_MODE_M 0x3 72#define DCU_MODE_S 0 73#define DCU_MODE_NORMAL 0x1 74#define DCU_MODE_TEST 0x2 75#define DCU_MODE_COLBAR 0x3 76#define RASTER_EN (1 << 14) /* Raster scan of pixel data */ | 60#include <machine/bus.h> 61#include <machine/fdt.h> 62#include <machine/cpu.h> 63#include <machine/intr.h> 64 65#include "fb_if.h" 66 67#include <arm/freescale/vybrid/vf_common.h> --- 4 unchanged lines hidden (view full) --- 72#define DCU_CTRLDESCCURSOR4 0x00C /* Control Descriptor Cursor 4 */ 73#define DCU_DCU_MODE 0x010 /* DCU4 Mode */ 74#define DCU_MODE_M 0x3 75#define DCU_MODE_S 0 76#define DCU_MODE_NORMAL 0x1 77#define DCU_MODE_TEST 0x2 78#define DCU_MODE_COLBAR 0x3 79#define RASTER_EN (1 << 14) /* Raster scan of pixel data */ |
80#define PDI_EN (1 << 13) 81#define PDI_DE_MODE (1 << 11) 82#define PDI_MODE_M 2 |
|
77#define DCU_BGND 0x014 /* Background */ 78#define DCU_DISP_SIZE 0x018 /* Display Size */ 79#define DELTA_M 0x7ff 80#define DELTA_Y_S 16 81#define DELTA_X_S 0 82#define DCU_HSYN_PARA 0x01C /* Horizontal Sync Parameter */ 83#define BP_H_SHIFT 22 84#define PW_H_SHIFT 11 85#define FP_H_SHIFT 0 86#define DCU_VSYN_PARA 0x020 /* Vertical Sync Parameter */ 87#define BP_V_SHIFT 22 88#define PW_V_SHIFT 11 89#define FP_V_SHIFT 0 90#define DCU_SYNPOL 0x024 /* Synchronize Polarity */ 91#define INV_HS (1 << 0) 92#define INV_VS (1 << 1) | 83#define DCU_BGND 0x014 /* Background */ 84#define DCU_DISP_SIZE 0x018 /* Display Size */ 85#define DELTA_M 0x7ff 86#define DELTA_Y_S 16 87#define DELTA_X_S 0 88#define DCU_HSYN_PARA 0x01C /* Horizontal Sync Parameter */ 89#define BP_H_SHIFT 22 90#define PW_H_SHIFT 11 91#define FP_H_SHIFT 0 92#define DCU_VSYN_PARA 0x020 /* Vertical Sync Parameter */ 93#define BP_V_SHIFT 22 94#define PW_V_SHIFT 11 95#define FP_V_SHIFT 0 96#define DCU_SYNPOL 0x024 /* Synchronize Polarity */ 97#define INV_HS (1 << 0) 98#define INV_VS (1 << 1) |
99#define INV_PDI_VS (1 << 8) /* Polarity of PDI input VSYNC. */ 100#define INV_PDI_HS (1 << 9) /* Polarity of PDI input HSYNC. */ 101#define INV_PDI_DE (1 << 10) /* Polarity of PDI input DE. */ |
|
93#define DCU_THRESHOLD 0x028 /* Threshold */ 94#define LS_BF_VS_SHIFT 16 95#define OUT_BUF_HIGH_SHIFT 8 96#define OUT_BUF_LOW_SHIFT 0 97#define DCU_INT_STATUS 0x02C /* Interrupt Status */ 98#define DCU_INT_MASK 0x030 /* Interrupt Mask */ 99#define DCU_COLBAR_1 0x034 /* COLBAR_1 */ 100#define DCU_COLBAR_2 0x038 /* COLBAR_2 */ --- 54 unchanged lines hidden (view full) --- 155#define BPP24 0x5 156#define EN_LAYER (1 << 31) /* Enable the layer */ 157#define DCU_CTRLDESCLn_5(n) DCU_CTRLDESCL(n, 5) 158#define DCU_CTRLDESCLn_6(n) DCU_CTRLDESCL(n, 6) 159#define DCU_CTRLDESCLn_7(n) DCU_CTRLDESCL(n, 7) 160#define DCU_CTRLDESCLn_8(n) DCU_CTRLDESCL(n, 8) 161#define DCU_CTRLDESCLn_9(n) DCU_CTRLDESCL(n, 9) 162 | 102#define DCU_THRESHOLD 0x028 /* Threshold */ 103#define LS_BF_VS_SHIFT 16 104#define OUT_BUF_HIGH_SHIFT 8 105#define OUT_BUF_LOW_SHIFT 0 106#define DCU_INT_STATUS 0x02C /* Interrupt Status */ 107#define DCU_INT_MASK 0x030 /* Interrupt Mask */ 108#define DCU_COLBAR_1 0x034 /* COLBAR_1 */ 109#define DCU_COLBAR_2 0x038 /* COLBAR_2 */ --- 54 unchanged lines hidden (view full) --- 164#define BPP24 0x5 165#define EN_LAYER (1 << 31) /* Enable the layer */ 166#define DCU_CTRLDESCLn_5(n) DCU_CTRLDESCL(n, 5) 167#define DCU_CTRLDESCLn_6(n) DCU_CTRLDESCL(n, 6) 168#define DCU_CTRLDESCLn_7(n) DCU_CTRLDESCL(n, 7) 169#define DCU_CTRLDESCLn_8(n) DCU_CTRLDESCL(n, 8) 170#define DCU_CTRLDESCLn_9(n) DCU_CTRLDESCL(n, 9) 171 |
163#define DISPLAY_WIDTH 480 164#define DISPLAY_HEIGHT 272 | 172#define NUM_LAYERS 64 |
165 | 173 |
174struct panel_info { 175 uint32_t width; 176 uint32_t height; 177 uint32_t h_back_porch; 178 uint32_t h_pulse_width; 179 uint32_t h_front_porch; 180 uint32_t v_back_porch; 181 uint32_t v_pulse_width; 182 uint32_t v_front_porch; 183 uint32_t clk_div; 184 uint32_t backlight_pin; 185}; 186 |
|
166struct dcu_softc { 167 struct resource *res[2]; 168 bus_space_tag_t bst; 169 bus_space_handle_t bsh; 170 void *ih; 171 device_t dev; 172 device_t sc_fbd; /* fbd child */ 173 struct fb_info sc_info; | 187struct dcu_softc { 188 struct resource *res[2]; 189 bus_space_tag_t bst; 190 bus_space_handle_t bsh; 191 void *ih; 192 device_t dev; 193 device_t sc_fbd; /* fbd child */ 194 struct fb_info sc_info; |
195 struct panel_info *panel; |
|
174}; 175 176static struct resource_spec dcu_spec[] = { 177 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 178 { SYS_RES_IRQ, 0, RF_ACTIVE }, 179 { -1, 0 } 180}; 181 --- 22 unchanged lines hidden (view full) --- 204 /* Ack interrupts */ 205 reg = READ4(sc, DCU_INT_STATUS); 206 WRITE4(sc, DCU_INT_STATUS, reg); 207 208 /* TODO interrupt handler */ 209} 210 211static int | 196}; 197 198static struct resource_spec dcu_spec[] = { 199 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 200 { SYS_RES_IRQ, 0, RF_ACTIVE }, 201 { -1, 0 } 202}; 203 --- 22 unchanged lines hidden (view full) --- 226 /* Ack interrupts */ 227 reg = READ4(sc, DCU_INT_STATUS); 228 WRITE4(sc, DCU_INT_STATUS, reg); 229 230 /* TODO interrupt handler */ 231} 232 233static int |
234get_panel_info(struct dcu_softc *sc, struct panel_info *panel) 235{ 236 phandle_t node; 237 pcell_t dts_value[3]; 238 int len; 239 240 if ((node = ofw_bus_get_node(sc->dev)) == -1) 241 return (ENXIO); 242 243 /* panel size */ 244 if ((len = OF_getproplen(node, "panel-size")) <= 0) 245 return (ENXIO); 246 OF_getprop(node, "panel-size", &dts_value, len); 247 panel->width = fdt32_to_cpu(dts_value[0]); 248 panel->height = fdt32_to_cpu(dts_value[1]); 249 250 /* hsync */ 251 if ((len = OF_getproplen(node, "panel-hsync")) <= 0) 252 return (ENXIO); 253 OF_getprop(node, "panel-hsync", &dts_value, len); 254 panel->h_back_porch = fdt32_to_cpu(dts_value[0]); 255 panel->h_pulse_width = fdt32_to_cpu(dts_value[1]); 256 panel->h_front_porch = fdt32_to_cpu(dts_value[2]); 257 258 /* vsync */ 259 if ((len = OF_getproplen(node, "panel-vsync")) <= 0) 260 return (ENXIO); 261 OF_getprop(node, "panel-vsync", &dts_value, len); 262 panel->v_back_porch = fdt32_to_cpu(dts_value[0]); 263 panel->v_pulse_width = fdt32_to_cpu(dts_value[1]); 264 panel->v_front_porch = fdt32_to_cpu(dts_value[2]); 265 266 /* clk divider */ 267 if ((len = OF_getproplen(node, "panel-clk-div")) <= 0) 268 return (ENXIO); 269 OF_getprop(node, "panel-clk-div", &dts_value, len); 270 panel->clk_div = fdt32_to_cpu(dts_value[0]); 271 272 /* backlight pin */ 273 if ((len = OF_getproplen(node, "panel-backlight-pin")) <= 0) 274 return (ENXIO); 275 OF_getprop(node, "panel-backlight-pin", &dts_value, len); 276 panel->backlight_pin = fdt32_to_cpu(dts_value[0]); 277 278 return (0); 279} 280 281static int |
|
212dcu_init(struct dcu_softc *sc) 213{ | 282dcu_init(struct dcu_softc *sc) 283{ |
284 struct panel_info *panel; |
|
214 int reg; | 285 int reg; |
286 int i; |
|
215 | 287 |
288 panel = sc->panel; 289 |
|
216 /* Configure DCU */ 217 reg = ((sc->sc_info.fb_height) << DELTA_Y_S); 218 reg |= (sc->sc_info.fb_width / 16); 219 WRITE4(sc, DCU_DISP_SIZE, reg); 220 | 290 /* Configure DCU */ 291 reg = ((sc->sc_info.fb_height) << DELTA_Y_S); 292 reg |= (sc->sc_info.fb_width / 16); 293 WRITE4(sc, DCU_DISP_SIZE, reg); 294 |
221 /* TODO: export panel info to FDT */ 222 223 reg = (2 << BP_H_SHIFT); 224 reg |= (41 << PW_H_SHIFT); 225 reg |= (2 << FP_H_SHIFT); | 295 reg = (panel->h_back_porch << BP_H_SHIFT); 296 reg |= (panel->h_pulse_width << PW_H_SHIFT); 297 reg |= (panel->h_front_porch << FP_H_SHIFT); |
226 WRITE4(sc, DCU_HSYN_PARA, reg); 227 | 298 WRITE4(sc, DCU_HSYN_PARA, reg); 299 |
228 reg = (2 << BP_V_SHIFT); 229 reg |= (10 << PW_V_SHIFT); 230 reg |= (2 << FP_V_SHIFT); | 300 reg = (panel->v_back_porch << BP_V_SHIFT); 301 reg |= (panel->v_pulse_width << PW_V_SHIFT); 302 reg |= (panel->v_front_porch << FP_V_SHIFT); |
231 WRITE4(sc, DCU_VSYN_PARA, reg); 232 233 WRITE4(sc, DCU_BGND, 0); | 303 WRITE4(sc, DCU_VSYN_PARA, reg); 304 305 WRITE4(sc, DCU_BGND, 0); |
234 WRITE4(sc, DCU_DIV_RATIO, 30); | 306 WRITE4(sc, DCU_DIV_RATIO, panel->clk_div); |
235 236 reg = (INV_VS | INV_HS); 237 WRITE4(sc, DCU_SYNPOL, reg); 238 | 307 308 reg = (INV_VS | INV_HS); 309 WRITE4(sc, DCU_SYNPOL, reg); 310 |
311 /* TODO: export to panel info */ |
|
239 reg = (0x3 << LS_BF_VS_SHIFT); 240 reg |= (0x78 << OUT_BUF_HIGH_SHIFT); 241 reg |= (0 << OUT_BUF_LOW_SHIFT); 242 WRITE4(sc, DCU_THRESHOLD, reg); 243 244 /* Mask all the interrupts */ 245 WRITE4(sc, DCU_INT_MASK, 0xffffffff); 246 | 312 reg = (0x3 << LS_BF_VS_SHIFT); 313 reg |= (0x78 << OUT_BUF_HIGH_SHIFT); 314 reg |= (0 << OUT_BUF_LOW_SHIFT); 315 WRITE4(sc, DCU_THRESHOLD, reg); 316 317 /* Mask all the interrupts */ 318 WRITE4(sc, DCU_INT_MASK, 0xffffffff); 319 |
320 /* Reset all layers */ 321 for (i = 0; i < NUM_LAYERS; i++) { 322 WRITE4(sc, DCU_CTRLDESCLn_1(i), 0x0); 323 WRITE4(sc, DCU_CTRLDESCLn_2(i), 0x0); 324 WRITE4(sc, DCU_CTRLDESCLn_3(i), 0x0); 325 WRITE4(sc, DCU_CTRLDESCLn_4(i), 0x0); 326 WRITE4(sc, DCU_CTRLDESCLn_5(i), 0x0); 327 WRITE4(sc, DCU_CTRLDESCLn_6(i), 0x0); 328 WRITE4(sc, DCU_CTRLDESCLn_7(i), 0x0); 329 WRITE4(sc, DCU_CTRLDESCLn_8(i), 0x0); 330 WRITE4(sc, DCU_CTRLDESCLn_9(i), 0x0); 331 } 332 |
|
247 /* Setup first layer */ 248 reg = (sc->sc_info.fb_width | (sc->sc_info.fb_height << 16)); 249 WRITE4(sc, DCU_CTRLDESCLn_1(0), reg); 250 WRITE4(sc, DCU_CTRLDESCLn_2(0), 0x0); 251 WRITE4(sc, DCU_CTRLDESCLn_3(0), sc->sc_info.fb_pbase); 252 reg = (BPP24 << BPP_SHIFT); 253 reg |= EN_LAYER; 254 reg |= (0xFF << TRANS_SHIFT); /* completely opaque */ --- 13 unchanged lines hidden (view full) --- 268 WRITE4(sc, DCU_UPDATE_MODE, READREG); 269 270 return (0); 271} 272 273static int 274dcu_attach(device_t dev) 275{ | 333 /* Setup first layer */ 334 reg = (sc->sc_info.fb_width | (sc->sc_info.fb_height << 16)); 335 WRITE4(sc, DCU_CTRLDESCLn_1(0), reg); 336 WRITE4(sc, DCU_CTRLDESCLn_2(0), 0x0); 337 WRITE4(sc, DCU_CTRLDESCLn_3(0), sc->sc_info.fb_pbase); 338 reg = (BPP24 << BPP_SHIFT); 339 reg |= EN_LAYER; 340 reg |= (0xFF << TRANS_SHIFT); /* completely opaque */ --- 13 unchanged lines hidden (view full) --- 354 WRITE4(sc, DCU_UPDATE_MODE, READREG); 355 356 return (0); 357} 358 359static int 360dcu_attach(device_t dev) 361{ |
362 struct panel_info panel; |
|
276 struct dcu_softc *sc; | 363 struct dcu_softc *sc; |
364 device_t gpio_dev; |
|
277 int err; 278 279 sc = device_get_softc(dev); | 365 int err; 366 367 sc = device_get_softc(dev); |
368 sc->dev = dev; |
|
280 281 if (bus_alloc_resources(dev, dcu_spec, sc->res)) { 282 device_printf(dev, "could not allocate resources\n"); 283 return (ENXIO); 284 } 285 286 /* Memory interface */ 287 sc->bst = rman_get_bustag(sc->res[0]); 288 sc->bsh = rman_get_bushandle(sc->res[0]); 289 290 /* Setup interrupt handler */ 291 err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE, 292 NULL, dcu_intr, sc, &sc->ih); 293 if (err) { 294 device_printf(dev, "Unable to alloc interrupt resource.\n"); 295 return (ENXIO); 296 } 297 | 369 370 if (bus_alloc_resources(dev, dcu_spec, sc->res)) { 371 device_printf(dev, "could not allocate resources\n"); 372 return (ENXIO); 373 } 374 375 /* Memory interface */ 376 sc->bst = rman_get_bustag(sc->res[0]); 377 sc->bsh = rman_get_bushandle(sc->res[0]); 378 379 /* Setup interrupt handler */ 380 err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE, 381 NULL, dcu_intr, sc, &sc->ih); 382 if (err) { 383 device_printf(dev, "Unable to alloc interrupt resource.\n"); 384 return (ENXIO); 385 } 386 |
387 if (get_panel_info(sc, &panel)) { 388 device_printf(dev, "Can't get panel info\n"); 389 return (ENXIO); 390 } 391 392 sc->panel = &panel; 393 |
|
298 /* Bypass timing control (used for raw lcd panels) */ 299 tcon_bypass(); 300 | 394 /* Bypass timing control (used for raw lcd panels) */ 395 tcon_bypass(); 396 |
301 sc->sc_info.fb_width = DISPLAY_WIDTH; 302 sc->sc_info.fb_height = DISPLAY_HEIGHT; | 397 /* Get the GPIO device, we need this to give power to USB */ 398 gpio_dev = devclass_get_device(devclass_find("gpio"), 0); 399 if (gpio_dev == NULL) { 400 device_printf(sc->dev, "Error: failed to get the GPIO dev\n"); 401 return (1); 402 } 403 404 /* Turn on backlight */ 405 /* TODO: Use FlexTimer/PWM */ 406 GPIO_PIN_SETFLAGS(gpio_dev, panel.backlight_pin, GPIO_PIN_OUTPUT); 407 GPIO_PIN_SET(gpio_dev, panel.backlight_pin, GPIO_PIN_HIGH); 408 409 sc->sc_info.fb_width = panel.width; 410 sc->sc_info.fb_height = panel.height; |
303 sc->sc_info.fb_stride = sc->sc_info.fb_width * 3; 304 sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 24; 305 sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride; 306 sc->sc_info.fb_vbase = (intptr_t)contigmalloc(sc->sc_info.fb_size, 307 M_DEVBUF, M_ZERO, 0, ~0, PAGE_SIZE, 0); 308 sc->sc_info.fb_pbase = (intptr_t)vtophys(sc->sc_info.fb_vbase); 309 310#if 0 --- 49 unchanged lines hidden --- | 411 sc->sc_info.fb_stride = sc->sc_info.fb_width * 3; 412 sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 24; 413 sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride; 414 sc->sc_info.fb_vbase = (intptr_t)contigmalloc(sc->sc_info.fb_size, 415 M_DEVBUF, M_ZERO, 0, ~0, PAGE_SIZE, 0); 416 sc->sc_info.fb_pbase = (intptr_t)vtophys(sc->sc_info.fb_vbase); 417 418#if 0 --- 49 unchanged lines hidden --- |