am335x_lcd.c revision 277632
1327Sjkh/*- 2327Sjkh * Copyright 2013 Oleksandr Tymoshenko <gonzo@freebsd.org> 3327Sjkh * All rights reserved. 4327Sjkh * 5327Sjkh * Redistribution and use in source and binary forms, with or without 6327Sjkh * modification, are permitted provided that the following conditions 7327Sjkh * are met: 8327Sjkh * 1. Redistributions of source code must retain the above copyright 9327Sjkh * notice, this list of conditions and the following disclaimer. 10327Sjkh * 2. Redistributions in binary form must reproduce the above copyright 11327Sjkh * notice, this list of conditions and the following disclaimer in the 12327Sjkh * documentation and/or other materials provided with the distribution. 13327Sjkh * 14327Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15327Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16327Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17327Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1831997Shoek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19327Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20327Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21327Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22327Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23327Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2474699Ssobomax * SUCH DAMAGE. 25327Sjkh */ 2655567Sphantom 2755567Sphantom#include <sys/cdefs.h> 2855567Sphantom__FBSDID("$FreeBSD: head/sys/arm/ti/am335x/am335x_lcd.c 277632 2015-01-24 01:53:28Z gonzo $"); 2955567Sphantom 30327Sjkh#include <sys/param.h> 3174699Ssobomax#include <sys/systm.h> 3255567Sphantom#include <sys/kernel.h> 33327Sjkh#include <sys/module.h> 3472174Ssobomax#include <sys/clock.h> 35411Sjkh#include <sys/time.h> 3684745Ssobomax#include <sys/bus.h> 3711780Sjkh#include <sys/lock.h> 38392Sjkh#include <sys/mutex.h> 3974699Ssobomax#include <sys/resource.h> 40327Sjkh#include <sys/rman.h> 4130221Scharnier#include <sys/sysctl.h> 4230221Scharnier#include <vm/vm.h> 43327Sjkh#include <vm/pmap.h> 44327Sjkh 45327Sjkh/* syscons bits */ 46327Sjkh#include <sys/fbio.h> 47327Sjkh#include <sys/consio.h> 4856001Sdan 49327Sjkh#include <machine/bus.h> 5074699Ssobomax 5174699Ssobomax#include <dev/fdt/fdt_common.h> 5274699Ssobomax#include <dev/ofw/openfirm.h> 5374699Ssobomax#include <dev/ofw/ofw_bus.h> 5474699Ssobomax#include <dev/ofw/ofw_bus_subr.h> 55327Sjkh 5646105Sjkh#include <dev/fb/fbreg.h> 5772174Ssobomax#include <dev/syscons/syscons.h> 5846105Sjkh 5946105Sjkh#include <arm/ti/ti_prcm.h> 6046105Sjkh#include <arm/ti/ti_scm.h> 61327Sjkh 62327Sjkh#include "am335x_lcd.h" 6372174Ssobomax#include "am335x_pwm.h" 64327Sjkh 65327Sjkh#define LCD_PID 0x00 66327Sjkh#define LCD_CTRL 0x04 67327Sjkh#define CTRL_DIV_MASK 0xff 68327Sjkh#define CTRL_DIV_SHIFT 8 69327Sjkh#define CTRL_AUTO_UFLOW_RESTART (1 << 1) 704996Sjkh#define CTRL_RASTER_MODE 1 71327Sjkh#define CTRL_LIDD_MODE 0 72327Sjkh#define LCD_LIDD_CTRL 0x0C 73327Sjkh#define LCD_LIDD_CS0_CONF 0x10 74327Sjkh#define LCD_LIDD_CS0_ADDR 0x14 75327Sjkh#define LCD_LIDD_CS0_DATA 0x18 76327Sjkh#define LCD_LIDD_CS1_CONF 0x1C 77327Sjkh#define LCD_LIDD_CS1_ADDR 0x20 78327Sjkh#define LCD_LIDD_CS1_DATA 0x24 79327Sjkh#define LCD_RASTER_CTRL 0x28 80327Sjkh#define RASTER_CTRL_TFT24_UNPACKED (1 << 26) 81327Sjkh#define RASTER_CTRL_TFT24 (1 << 25) 82327Sjkh#define RASTER_CTRL_STN565 (1 << 24) 83327Sjkh#define RASTER_CTRL_TFTPMAP (1 << 23) 84327Sjkh#define RASTER_CTRL_NIBMODE (1 << 22) 85327Sjkh#define RASTER_CTRL_PALMODE_SHIFT 20 86327Sjkh#define PALETTE_PALETTE_AND_DATA 0x00 87327Sjkh#define PALETTE_PALETTE_ONLY 0x01 88327Sjkh#define PALETTE_DATA_ONLY 0x02 894996Sjkh#define RASTER_CTRL_REQDLY_SHIFT 12 904996Sjkh#define RASTER_CTRL_MONO8B (1 << 9) 914996Sjkh#define RASTER_CTRL_RBORDER (1 << 8) 924996Sjkh#define RASTER_CTRL_LCDTFT (1 << 7) 93327Sjkh#define RASTER_CTRL_LCDBW (1 << 1) 94327Sjkh#define RASTER_CTRL_LCDEN (1 << 0) 95327Sjkh#define LCD_RASTER_TIMING_0 0x2C 96327Sjkh#define RASTER_TIMING_0_HBP_SHIFT 24 9771965Sjkh#define RASTER_TIMING_0_HFP_SHIFT 16 9871965Sjkh#define RASTER_TIMING_0_HSW_SHIFT 10 9971965Sjkh#define RASTER_TIMING_0_PPLLSB_SHIFT 4 10071965Sjkh#define RASTER_TIMING_0_PPLMSB_SHIFT 3 10172174Ssobomax#define LCD_RASTER_TIMING_1 0x30 10272174Ssobomax#define RASTER_TIMING_1_VBP_SHIFT 24 10372174Ssobomax#define RASTER_TIMING_1_VFP_SHIFT 16 10472174Ssobomax#define RASTER_TIMING_1_VSW_SHIFT 10 105327Sjkh#define RASTER_TIMING_1_LPP_SHIFT 0 106327Sjkh#define LCD_RASTER_TIMING_2 0x34 107327Sjkh#define RASTER_TIMING_2_HSWHI_SHIFT 27 108327Sjkh#define RASTER_TIMING_2_LPP_B10_SHIFT 26 109327Sjkh#define RASTER_TIMING_2_PHSVS (1 << 25) 110327Sjkh#define RASTER_TIMING_2_PHSVS_RISE (1 << 24) 111327Sjkh#define RASTER_TIMING_2_PHSVS_FALL (0 << 24) 112327Sjkh#define RASTER_TIMING_2_IOE (1 << 23) 113327Sjkh#define RASTER_TIMING_2_IPC (1 << 22) 114327Sjkh#define RASTER_TIMING_2_IHS (1 << 21) 115327Sjkh#define RASTER_TIMING_2_IVS (1 << 20) 116327Sjkh#define RASTER_TIMING_2_ACBI_SHIFT 16 1174996Sjkh#define RASTER_TIMING_2_ACB_SHIFT 8 1184996Sjkh#define RASTER_TIMING_2_HBPHI_SHIFT 4 1194996Sjkh#define RASTER_TIMING_2_HFPHI_SHIFT 0 1204996Sjkh#define LCD_RASTER_SUBPANEL 0x38 121411Sjkh#define LCD_RASTER_SUBPANEL2 0x3C 122411Sjkh#define LCD_LCDDMA_CTRL 0x40 123411Sjkh#define LCDDMA_CTRL_DMA_MASTER_PRIO_SHIFT 16 124411Sjkh#define LCDDMA_CTRL_TH_FIFO_RDY_SHIFT 8 1254996Sjkh#define LCDDMA_CTRL_BURST_SIZE_SHIFT 4 1264996Sjkh#define LCDDMA_CTRL_BYTES_SWAP (1 << 3) 1274996Sjkh#define LCDDMA_CTRL_BE (1 << 1) 1284996Sjkh#define LCDDMA_CTRL_FB0_ONLY 0 12972174Ssobomax#define LCDDMA_CTRL_FB0_FB1 (1 << 0) 13072174Ssobomax#define LCD_LCDDMA_FB0_BASE 0x44 13172174Ssobomax#define LCD_LCDDMA_FB0_CEILING 0x48 13262775Ssobomax#define LCD_LCDDMA_FB1_BASE 0x4C 13367454Ssobomax#define LCD_LCDDMA_FB1_CEILING 0x50 13467454Ssobomax#define LCD_SYSCONFIG 0x54 13567454Ssobomax#define SYSCONFIG_STANDBY_FORCE (0 << 4) 13667454Ssobomax#define SYSCONFIG_STANDBY_NONE (1 << 4) 137379Sjkh#define SYSCONFIG_STANDBY_SMART (2 << 4) 138379Sjkh#define SYSCONFIG_IDLE_FORCE (0 << 2) 139379Sjkh#define SYSCONFIG_IDLE_NONE (1 << 2) 140379Sjkh#define SYSCONFIG_IDLE_SMART (2 << 2) 141411Sjkh#define LCD_IRQSTATUS_RAW 0x58 142411Sjkh#define LCD_IRQSTATUS 0x5C 143411Sjkh#define LCD_IRQENABLE_SET 0x60 144411Sjkh#define LCD_IRQENABLE_CLEAR 0x64 145383Sjkh#define IRQ_EOF1 (1 << 9) 14611780Sjkh#define IRQ_EOF0 (1 << 8) 147383Sjkh#define IRQ_PL (1 << 6) 148383Sjkh#define IRQ_FUF (1 << 5) 14972174Ssobomax#define IRQ_ACB (1 << 3) 15072174Ssobomax#define IRQ_SYNC_LOST (1 << 2) 15172174Ssobomax#define IRQ_RASTER_DONE (1 << 1) 15272174Ssobomax#define IRQ_FRAME_DONE (1 << 0) 153392Sjkh#define LCD_END_OF_INT_IND 0x68 154392Sjkh#define LCD_CLKC_ENABLE 0x6C 155392Sjkh#define CLKC_ENABLE_DMA (1 << 2) 156392Sjkh#define CLKC_ENABLE_LDID (1 << 1) 15774699Ssobomax#define CLKC_ENABLE_CORE (1 << 0) 15874699Ssobomax#define LCD_CLKC_RESET 0x70 15974699Ssobomax#define CLKC_RESET_MAIN (1 << 3) 16074699Ssobomax#define CLKC_RESET_DMA (1 << 2) 16174699Ssobomax#define CLKC_RESET_LDID (1 << 1) 16274699Ssobomax#define CLKC_RESET_CORE (1 << 0) 16374699Ssobomax 16474699Ssobomax#define LCD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 16574699Ssobomax#define LCD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 16674699Ssobomax#define LCD_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ 16774699Ssobomax device_get_nameunit(_sc->sc_dev), "am335x_lcd", MTX_DEF) 16874699Ssobomax#define LCD_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx); 16974699Ssobomax 17074699Ssobomax#define LCD_READ4(_sc, reg) bus_read_4((_sc)->sc_mem_res, reg); 171327Sjkh#define LCD_WRITE4(_sc, reg, value) \ 172327Sjkh bus_write_4((_sc)->sc_mem_res, reg, value); 173327Sjkh 17430221Scharnier 175327Sjkh/* Backlight is controlled by eCAS interface on PWM unit 0 */ 176327Sjkh#define PWM_UNIT 0 17746105Sjkh#define PWM_PERIOD 100 178327Sjkh 1798857Srgrimesstruct am335x_lcd_softc { 180327Sjkh device_t sc_dev; 181327Sjkh struct resource *sc_mem_res; 182327Sjkh struct resource *sc_irq_res; 183327Sjkh void *sc_intr_hl; 1844996Sjkh struct mtx sc_mtx; 185327Sjkh int sc_backlight; 186327Sjkh struct sysctl_oid *sc_oid; 18760563Ssteve 18872174Ssobomax /* Framebuffer */ 18972174Ssobomax bus_dma_tag_t sc_dma_tag; 19072174Ssobomax bus_dmamap_t sc_dma_map; 19172174Ssobomax size_t sc_fb_size; 19272174Ssobomax bus_addr_t sc_fb_phys; 19372174Ssobomax uint8_t *sc_fb_base; 19472174Ssobomax}; 19572174Ssobomax 19672174Ssobomaxstatic void 19772174Ssobomaxam335x_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 19872174Ssobomax{ 19972174Ssobomax bus_addr_t *addr; 20072174Ssobomax 20172174Ssobomax if (err) 20272174Ssobomax return; 20360563Ssteve 20460563Ssteve addr = (bus_addr_t*)arg; 20556001Sdan *addr = segs[0].ds_addr; 206327Sjkh} 207327Sjkh 20874699Ssobomaxstatic uint32_t 20974699Ssobomaxam335x_lcd_calc_divisor(uint32_t reference, uint32_t freq) 21030221Scharnier{ 211327Sjkh uint32_t div; 212327Sjkh /* Raster mode case: divisors are in range from 2 to 255 */ 213327Sjkh for (div = 2; div < 255; div++) 214327Sjkh if (reference/div <= freq) 21530221Scharnier return (div); 21630221Scharnier 217327Sjkh return (255); 21830221Scharnier} 21972978Ssobomax 22074699Ssobomaxstatic int 22130221Scharnieram335x_lcd_sysctl_backlight(SYSCTL_HANDLER_ARGS) 222327Sjkh{ 223327Sjkh struct am335x_lcd_softc *sc = (struct am335x_lcd_softc*)arg1; 224 int error; 225 int backlight; 226 227 backlight = sc->sc_backlight; 228 error = sysctl_handle_int(oidp, &backlight, 0, req); 229 230 if (error != 0 || req->newptr == NULL) 231 return (error); 232 233 if (backlight < 0) 234 backlight = 0; 235 if (backlight > 100) 236 backlight = 100; 237 238 LCD_LOCK(sc); 239 error = am335x_pwm_config_ecas(PWM_UNIT, PWM_PERIOD, 240 backlight*PWM_PERIOD/100); 241 if (error == 0) 242 sc->sc_backlight = backlight; 243 LCD_UNLOCK(sc); 244 245 return (error); 246} 247 248static int 249am335x_read_panel_property(device_t dev, const char *name, uint32_t *val) 250{ 251 phandle_t node; 252 pcell_t cell; 253 254 node = ofw_bus_get_node(dev); 255 if ((OF_getprop(node, name, &cell, sizeof(cell))) <= 0) { 256 device_printf(dev, "missing '%s' attribute in LCD panel info\n", 257 name); 258 return (ENXIO); 259 } 260 261 *val = fdt32_to_cpu(cell); 262 263 return (0); 264} 265 266static int 267am335x_read_panel_info(device_t dev, struct panel_info *panel) 268{ 269 int error; 270 271 error = 0; 272 if ((error = am335x_read_panel_property(dev, 273 "panel_width", &panel->panel_width))) 274 goto out; 275 276 if ((error = am335x_read_panel_property(dev, 277 "panel_height", &panel->panel_height))) 278 goto out; 279 280 if ((error = am335x_read_panel_property(dev, 281 "panel_hfp", &panel->panel_hfp))) 282 goto out; 283 284 if ((error = am335x_read_panel_property(dev, 285 "panel_hbp", &panel->panel_hbp))) 286 goto out; 287 288 if ((error = am335x_read_panel_property(dev, 289 "panel_hsw", &panel->panel_hsw))) 290 goto out; 291 292 if ((error = am335x_read_panel_property(dev, 293 "panel_vfp", &panel->panel_vfp))) 294 goto out; 295 296 if ((error = am335x_read_panel_property(dev, 297 "panel_vbp", &panel->panel_vbp))) 298 goto out; 299 300 if ((error = am335x_read_panel_property(dev, 301 "panel_vsw", &panel->panel_vsw))) 302 goto out; 303 304 if ((error = am335x_read_panel_property(dev, 305 "panel_pxl_clk", &panel->panel_pxl_clk))) 306 goto out; 307 308 if ((error = am335x_read_panel_property(dev, 309 "panel_invert_pxl_clk", &panel->panel_invert_pxl_clk))) 310 goto out; 311 312 if ((error = am335x_read_panel_property(dev, 313 "ac_bias", &panel->ac_bias))) 314 goto out; 315 316 if ((error = am335x_read_panel_property(dev, 317 "ac_bias_intrpt", &panel->ac_bias_intrpt))) 318 goto out; 319 320 if ((error = am335x_read_panel_property(dev, 321 "dma_burst_sz", &panel->dma_burst_sz))) 322 goto out; 323 324 if ((error = am335x_read_panel_property(dev, 325 "bpp", &panel->bpp))) 326 goto out; 327 328 if ((error = am335x_read_panel_property(dev, 329 "fdd", &panel->fdd))) 330 goto out; 331 332 if ((error = am335x_read_panel_property(dev, 333 "invert_line_clock", &panel->invert_line_clock))) 334 goto out; 335 336 if ((error = am335x_read_panel_property(dev, 337 "invert_frm_clock", &panel->invert_frm_clock))) 338 goto out; 339 340 if ((error = am335x_read_panel_property(dev, 341 "sync_edge", &panel->sync_edge))) 342 goto out; 343 344 error = am335x_read_panel_property(dev, 345 "sync_ctrl", &panel->sync_ctrl); 346 347out: 348 return (error); 349} 350 351static void 352am335x_lcd_intr(void *arg) 353{ 354 struct am335x_lcd_softc *sc = arg; 355 uint32_t reg; 356 357 reg = LCD_READ4(sc, LCD_IRQSTATUS); 358 LCD_WRITE4(sc, LCD_IRQSTATUS, reg); 359 /* Read value back to make sure it reached the hardware */ 360 reg = LCD_READ4(sc, LCD_IRQSTATUS); 361 362 if (reg & IRQ_SYNC_LOST) { 363 reg = LCD_READ4(sc, LCD_RASTER_CTRL); 364 reg &= ~RASTER_CTRL_LCDEN; 365 LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); 366 367 reg = LCD_READ4(sc, LCD_RASTER_CTRL); 368 reg |= RASTER_CTRL_LCDEN; 369 LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); 370 goto done; 371 } 372 373 if (reg & IRQ_PL) { 374 reg = LCD_READ4(sc, LCD_RASTER_CTRL); 375 reg &= ~RASTER_CTRL_LCDEN; 376 LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); 377 378 reg = LCD_READ4(sc, LCD_RASTER_CTRL); 379 reg |= RASTER_CTRL_LCDEN; 380 LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); 381 goto done; 382 } 383 384 if (reg & IRQ_EOF0) { 385 LCD_WRITE4(sc, LCD_LCDDMA_FB0_BASE, sc->sc_fb_phys); 386 LCD_WRITE4(sc, LCD_LCDDMA_FB0_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); 387 reg &= ~IRQ_EOF0; 388 } 389 390 if (reg & IRQ_EOF1) { 391 LCD_WRITE4(sc, LCD_LCDDMA_FB1_BASE, sc->sc_fb_phys); 392 LCD_WRITE4(sc, LCD_LCDDMA_FB1_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); 393 reg &= ~IRQ_EOF1; 394 } 395 396 if (reg & IRQ_FUF) { 397 /* TODO: Handle FUF */ 398 } 399 400 if (reg & IRQ_ACB) { 401 /* TODO: Handle ACB */ 402 } 403 404done: 405 LCD_WRITE4(sc, LCD_END_OF_INT_IND, 0); 406 /* Read value back to make sure it reached the hardware */ 407 reg = LCD_READ4(sc, LCD_END_OF_INT_IND); 408} 409 410static int 411am335x_lcd_probe(device_t dev) 412{ 413 int err; 414 415 if (!ofw_bus_status_okay(dev)) 416 return (ENXIO); 417 418 if (!ofw_bus_is_compatible(dev, "ti,am335x-lcd")) 419 return (ENXIO); 420 421 device_set_desc(dev, "AM335x LCD controller"); 422 423 err = sc_probe_unit(device_get_unit(dev), 424 device_get_flags(dev) | SC_AUTODETECT_KBD); 425 if (err != 0) 426 return (err); 427 428 return (BUS_PROBE_DEFAULT); 429} 430 431static int 432am335x_lcd_attach(device_t dev) 433{ 434 struct am335x_lcd_softc *sc; 435 int rid; 436 int div; 437 struct panel_info panel; 438 uint32_t reg, timing0, timing1, timing2; 439 struct sysctl_ctx_list *ctx; 440 struct sysctl_oid *tree; 441 uint32_t burst_log; 442 int err; 443 size_t dma_size; 444 uint32_t hbp, hfp, hsw; 445 uint32_t vbp, vfp, vsw; 446 uint32_t width, height; 447 448 sc = device_get_softc(dev); 449 sc->sc_dev = dev; 450 451 if (am335x_read_panel_info(dev, &panel)) 452 return (ENXIO); 453 454 int ref_freq = 0; 455 ti_prcm_clk_enable(LCDC_CLK); 456 if (ti_prcm_clk_get_source_freq(LCDC_CLK, &ref_freq)) { 457 device_printf(dev, "Can't get reference frequency\n"); 458 return (ENXIO); 459 } 460 461 rid = 0; 462 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 463 RF_ACTIVE); 464 if (!sc->sc_mem_res) { 465 device_printf(dev, "cannot allocate memory window\n"); 466 return (ENXIO); 467 } 468 469 rid = 0; 470 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 471 RF_ACTIVE); 472 if (!sc->sc_irq_res) { 473 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 474 device_printf(dev, "cannot allocate interrupt\n"); 475 return (ENXIO); 476 } 477 478 if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 479 NULL, am335x_lcd_intr, sc, 480 &sc->sc_intr_hl) != 0) { 481 bus_release_resource(dev, SYS_RES_IRQ, rid, 482 sc->sc_irq_res); 483 bus_release_resource(dev, SYS_RES_MEMORY, rid, 484 sc->sc_mem_res); 485 device_printf(dev, "Unable to setup the irq handler.\n"); 486 return (ENXIO); 487 } 488 489 LCD_LOCK_INIT(sc); 490 491 /* Panle initialization */ 492 dma_size = round_page(panel.panel_width*panel.panel_height*panel.bpp/8); 493 494 /* 495 * Now allocate framebuffer memory 496 */ 497 err = bus_dma_tag_create( 498 bus_get_dma_tag(dev), 499 4, 0, /* alignment, boundary */ 500 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 501 BUS_SPACE_MAXADDR, /* highaddr */ 502 NULL, NULL, /* filter, filterarg */ 503 dma_size, 1, /* maxsize, nsegments */ 504 dma_size, 0, /* maxsegsize, flags */ 505 NULL, NULL, /* lockfunc, lockarg */ 506 &sc->sc_dma_tag); 507 if (err) 508 goto fail; 509 510 err = bus_dmamem_alloc(sc->sc_dma_tag, (void **)&sc->sc_fb_base, 511 BUS_DMA_COHERENT, &sc->sc_dma_map); 512 513 if (err) { 514 device_printf(dev, "cannot allocate framebuffer\n"); 515 goto fail; 516 } 517 518 err = bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, sc->sc_fb_base, 519 dma_size, am335x_fb_dmamap_cb, &sc->sc_fb_phys, BUS_DMA_NOWAIT); 520 521 if (err) { 522 device_printf(dev, "cannot load DMA map\n"); 523 goto fail; 524 } 525 526 /* Make sure it's blank */ 527 memset(sc->sc_fb_base, 0x00, dma_size); 528 529 /* Calculate actual FB Size */ 530 sc->sc_fb_size = panel.panel_width*panel.panel_height*panel.bpp/8; 531 532 /* Only raster mode is supported */ 533 reg = CTRL_RASTER_MODE; 534 div = am335x_lcd_calc_divisor(ref_freq, panel.panel_pxl_clk); 535 reg |= (div << CTRL_DIV_SHIFT); 536 LCD_WRITE4(sc, LCD_CTRL, reg); 537 538 /* Set timing */ 539 timing0 = timing1 = timing2 = 0; 540 541 hbp = panel.panel_hbp - 1; 542 hfp = panel.panel_hfp - 1; 543 hsw = panel.panel_hsw - 1; 544 545 vbp = panel.panel_vbp; 546 vfp = panel.panel_vfp; 547 vsw = panel.panel_vsw - 1; 548 549 height = panel.panel_height - 1; 550 width = panel.panel_width - 1; 551 552 /* Horizontal back porch */ 553 timing0 |= (hbp & 0xff) << RASTER_TIMING_0_HBP_SHIFT; 554 timing2 |= ((hbp >> 8) & 3) << RASTER_TIMING_2_HBPHI_SHIFT; 555 /* Horizontal front porch */ 556 timing0 |= (hfp & 0xff) << RASTER_TIMING_0_HFP_SHIFT; 557 timing2 |= ((hfp >> 8) & 3) << RASTER_TIMING_2_HFPHI_SHIFT; 558 /* Horizontal sync width */ 559 timing0 |= (hsw & 0x3f) << RASTER_TIMING_0_HSW_SHIFT; 560 timing2 |= ((hsw >> 6) & 0xf) << RASTER_TIMING_2_HSWHI_SHIFT; 561 562 /* Vertical back porch, front porch, sync width */ 563 timing1 |= (vbp & 0xff) << RASTER_TIMING_1_VBP_SHIFT; 564 timing1 |= (vfp & 0xff) << RASTER_TIMING_1_VFP_SHIFT; 565 timing1 |= (vsw & 0x3f) << RASTER_TIMING_1_VSW_SHIFT; 566 567 /* Pixels per line */ 568 timing0 |= ((width >> 10) & 1) 569 << RASTER_TIMING_0_PPLMSB_SHIFT; 570 timing0 |= ((width >> 4) & 0x3f) 571 << RASTER_TIMING_0_PPLLSB_SHIFT; 572 573 /* Lines per panel */ 574 timing1 |= (height & 0x3ff) 575 << RASTER_TIMING_1_LPP_SHIFT; 576 timing2 |= ((height >> 10 ) & 1) 577 << RASTER_TIMING_2_LPP_B10_SHIFT; 578 579 /* clock signal settings */ 580 if (panel.sync_ctrl) 581 timing2 |= RASTER_TIMING_2_PHSVS; 582 if (panel.sync_edge) 583 timing2 |= RASTER_TIMING_2_PHSVS_RISE; 584 else 585 timing2 |= RASTER_TIMING_2_PHSVS_FALL; 586 if (panel.invert_line_clock) 587 timing2 |= RASTER_TIMING_2_IHS; 588 if (panel.invert_frm_clock) 589 timing2 |= RASTER_TIMING_2_IVS; 590 if (panel.panel_invert_pxl_clk) 591 timing2 |= RASTER_TIMING_2_IPC; 592 593 /* AC bias */ 594 timing2 |= (panel.ac_bias << RASTER_TIMING_2_ACB_SHIFT); 595 timing2 |= (panel.ac_bias_intrpt << RASTER_TIMING_2_ACBI_SHIFT); 596 597 LCD_WRITE4(sc, LCD_RASTER_TIMING_0, timing0); 598 LCD_WRITE4(sc, LCD_RASTER_TIMING_1, timing1); 599 LCD_WRITE4(sc, LCD_RASTER_TIMING_2, timing2); 600 601 /* DMA settings */ 602 reg = LCDDMA_CTRL_FB0_FB1; 603 /* Find power of 2 for current burst size */ 604 switch (panel.dma_burst_sz) { 605 case 1: 606 burst_log = 0; 607 break; 608 case 2: 609 burst_log = 1; 610 break; 611 case 4: 612 burst_log = 2; 613 break; 614 case 8: 615 burst_log = 3; 616 break; 617 case 16: 618 default: 619 burst_log = 4; 620 break; 621 } 622 reg |= (burst_log << LCDDMA_CTRL_BURST_SIZE_SHIFT); 623 /* XXX: FIFO TH */ 624 reg |= (0 << LCDDMA_CTRL_TH_FIFO_RDY_SHIFT); 625 LCD_WRITE4(sc, LCD_LCDDMA_CTRL, reg); 626 627 LCD_WRITE4(sc, LCD_LCDDMA_FB0_BASE, sc->sc_fb_phys); 628 LCD_WRITE4(sc, LCD_LCDDMA_FB0_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); 629 LCD_WRITE4(sc, LCD_LCDDMA_FB1_BASE, sc->sc_fb_phys); 630 LCD_WRITE4(sc, LCD_LCDDMA_FB1_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); 631 632 /* Enable LCD */ 633 reg = RASTER_CTRL_LCDTFT; 634 reg |= (panel.fdd << RASTER_CTRL_REQDLY_SHIFT); 635 reg |= (PALETTE_DATA_ONLY << RASTER_CTRL_PALMODE_SHIFT); 636 if (panel.bpp >= 24) 637 reg |= RASTER_CTRL_TFT24; 638 if (panel.bpp == 32) 639 reg |= RASTER_CTRL_TFT24_UNPACKED; 640 LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); 641 642 LCD_WRITE4(sc, LCD_CLKC_ENABLE, 643 CLKC_ENABLE_DMA | CLKC_ENABLE_LDID | CLKC_ENABLE_CORE); 644 645 LCD_WRITE4(sc, LCD_CLKC_RESET, CLKC_RESET_MAIN); 646 DELAY(100); 647 LCD_WRITE4(sc, LCD_CLKC_RESET, 0); 648 649 reg = IRQ_EOF1 | IRQ_EOF0 | IRQ_FUF | IRQ_PL | 650 IRQ_ACB | IRQ_SYNC_LOST | IRQ_RASTER_DONE | 651 IRQ_FRAME_DONE; 652 LCD_WRITE4(sc, LCD_IRQENABLE_SET, reg); 653 654 reg = LCD_READ4(sc, LCD_RASTER_CTRL); 655 reg |= RASTER_CTRL_LCDEN; 656 LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); 657 658 LCD_WRITE4(sc, LCD_SYSCONFIG, 659 SYSCONFIG_STANDBY_SMART | SYSCONFIG_IDLE_SMART); 660 661 /* Init backlight interface */ 662 ctx = device_get_sysctl_ctx(sc->sc_dev); 663 tree = device_get_sysctl_tree(sc->sc_dev); 664 sc->sc_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 665 "backlight", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 666 am335x_lcd_sysctl_backlight, "I", "LCD backlight"); 667 sc->sc_backlight = 0; 668 /* Check if eCAS interface is available at this point */ 669 if (am335x_pwm_config_ecas(PWM_UNIT, 670 PWM_PERIOD, PWM_PERIOD) == 0) 671 sc->sc_backlight = 100; 672 673 err = (sc_attach_unit(device_get_unit(dev), 674 device_get_flags(dev) | SC_AUTODETECT_KBD)); 675 676 if (err) { 677 device_printf(dev, "failed to attach syscons\n"); 678 goto fail; 679 } 680 681 am335x_lcd_syscons_setup((vm_offset_t)sc->sc_fb_base, sc->sc_fb_phys, &panel); 682 683 return (0); 684 685fail: 686 return (err); 687} 688 689static int 690am335x_lcd_detach(device_t dev) 691{ 692 /* Do not let unload driver */ 693 return (EBUSY); 694} 695 696static device_method_t am335x_lcd_methods[] = { 697 DEVMETHOD(device_probe, am335x_lcd_probe), 698 DEVMETHOD(device_attach, am335x_lcd_attach), 699 DEVMETHOD(device_detach, am335x_lcd_detach), 700 701 DEVMETHOD_END 702}; 703 704static driver_t am335x_lcd_driver = { 705 "am335x_lcd", 706 am335x_lcd_methods, 707 sizeof(struct am335x_lcd_softc), 708}; 709 710static devclass_t am335x_lcd_devclass; 711 712DRIVER_MODULE(am335x_lcd, simplebus, am335x_lcd_driver, am335x_lcd_devclass, 0, 0); 713MODULE_VERSION(am335x_lcd, 1); 714MODULE_DEPEND(am335x_lcd, simplebus, 1, 1, 1); 715