From fbd5aeda481526c5c23cb913461378423bdb2137 Mon Sep 17 00:00:00 2001 From: Hannes Petermaier Date: Tue, 3 Feb 2015 13:22:26 +0100 Subject: board/BuR/common: Take usage of am335x LCD-Display a summary screen to the lcd. Values are taken from environment and or devicetree blob. Signed-off-by: Hannes Petermaier --- board/BuR/common/bur_common.h | 4 + board/BuR/common/common.c | 417 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 420 insertions(+), 1 deletion(-) (limited to 'board/BuR/common') diff --git a/board/BuR/common/bur_common.h b/board/BuR/common/bur_common.h index 15225b0..39afbba 100644 --- a/board/BuR/common/bur_common.h +++ b/board/BuR/common/bur_common.h @@ -12,6 +12,10 @@ #ifndef _BUR_COMMON_H_ #define _BUR_COMMON_H_ +#include <../../../drivers/video/am335x-fb.h> + +int load_lcdtiming(struct am335x_lcdpanel *panel); +void br_summaryscreen(void); void blink(u32 blinks, u32 intervall, u32 pin); void pmicsetup(u32 mpupll); void enable_uart0_pin_mux(void); diff --git a/board/BuR/common/common.c b/board/BuR/common/common.c index 25cbe62..7d0e05c 100644 --- a/board/BuR/common/common.c +++ b/board/BuR/common/common.c @@ -9,7 +9,7 @@ * SPDX-License-Identifier: GPL-2.0+ * */ - +#include #include #include #include @@ -26,10 +26,421 @@ #include #include #include +#include +#include +#ifdef CONFIG_USE_FDT + #include +#endif #include "bur_common.h" +#include "../../../drivers/video/am335x-fb.h" static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_USE_FDT + #define FDTPROP(a, b, c) fdt_getprop_u32_default((void *)a, b, c, ~0UL) + #define PATHTIM "/panel/display-timings/default" + #define PATHINF "/panel/panel-info" +#endif /* --------------------------------------------------------------------------*/ +#if defined(CONFIG_LCD) && defined(CONFIG_AM335X_LCD) && \ + !defined(CONFIG_SPL_BUILD) +int load_lcdtiming(struct am335x_lcdpanel *panel) +{ + struct am335x_lcdpanel pnltmp; +#ifdef CONFIG_USE_FDT + u32 dtbaddr = getenv_ulong("dtbaddr", 16, ~0UL); + u32 dtbprop; + + if (dtbaddr == ~0UL) { + puts("load_lcdtiming: failed to get 'dtbaddr' from env!\n"); + return -1; + } + memcpy(&pnltmp, (void *)panel, sizeof(struct am335x_lcdpanel)); + + pnltmp.hactive = FDTPROP(dtbaddr, PATHTIM, "hactive"); + pnltmp.vactive = FDTPROP(dtbaddr, PATHTIM, "vactive"); + pnltmp.bpp = FDTPROP(dtbaddr, PATHINF, "bpp"); + pnltmp.hfp = FDTPROP(dtbaddr, PATHTIM, "hfront-porch"); + pnltmp.hbp = FDTPROP(dtbaddr, PATHTIM, "hback-porch"); + pnltmp.hsw = FDTPROP(dtbaddr, PATHTIM, "hsync-len"); + pnltmp.vfp = FDTPROP(dtbaddr, PATHTIM, "vfront-porch"); + pnltmp.vbp = FDTPROP(dtbaddr, PATHTIM, "vback-porch"); + pnltmp.vsw = FDTPROP(dtbaddr, PATHTIM, "vsync-len"); + pnltmp.pup_delay = FDTPROP(dtbaddr, PATHTIM, "pupdelay"); + pnltmp.pon_delay = FDTPROP(dtbaddr, PATHTIM, "pondelay"); + + /* calc. proper clk-divisor */ + dtbprop = FDTPROP(dtbaddr, PATHTIM, "clock-frequency"); + if (dtbprop != ~0UL) + pnltmp.pxl_clk_div = 192000000 / dtbprop; + else + pnltmp.pxl_clk_div = ~0UL; + + /* check polarity of control-signals */ + dtbprop = FDTPROP(dtbaddr, PATHTIM, "hsync-active"); + if (dtbprop == 0) + pnltmp.pol |= HSYNC_INVERT; + dtbprop = FDTPROP(dtbaddr, PATHTIM, "vsync-active"); + if (dtbprop == 0) + pnltmp.pol |= VSYNC_INVERT; + dtbprop = FDTPROP(dtbaddr, PATHINF, "sync-ctrl"); + if (dtbprop == 1) + pnltmp.pol |= HSVS_CONTROL; + dtbprop = FDTPROP(dtbaddr, PATHINF, "sync-edge"); + if (dtbprop == 1) + pnltmp.pol |= HSVS_RISEFALL; + dtbprop = FDTPROP(dtbaddr, PATHTIM, "pixelclk-active"); + if (dtbprop == 0) + pnltmp.pol |= PXCLK_INVERT; + dtbprop = FDTPROP(dtbaddr, PATHTIM, "de-active"); + if (dtbprop == 0) + pnltmp.pol |= DE_INVERT; +#else + pnltmp.hactive = getenv_ulong("ds1_hactive", 10, ~0UL); + pnltmp.vactive = getenv_ulong("ds1_vactive", 10, ~0UL); + pnltmp.bpp = getenv_ulong("ds1_bpp", 10, ~0UL); + pnltmp.hfp = getenv_ulong("ds1_hfp", 10, ~0UL); + pnltmp.hbp = getenv_ulong("ds1_hbp", 10, ~0UL); + pnltmp.hsw = getenv_ulong("ds1_hsw", 10, ~0UL); + pnltmp.vfp = getenv_ulong("ds1_vfp", 10, ~0UL); + pnltmp.vbp = getenv_ulong("ds1_vbp", 10, ~0UL); + pnltmp.vsw = getenv_ulong("ds1_vsw", 10, ~0UL); + pnltmp.pxl_clk_div = getenv_ulong("ds1_pxlclkdiv", 10, ~0UL); + pnltmp.pol = getenv_ulong("ds1_pol", 16, ~0UL); + pnltmp.pup_delay = getenv_ulong("ds1_pupdelay", 10, ~0UL); + pnltmp.pon_delay = getenv_ulong("ds1_tondelay", 10, ~0UL); +#endif + if ( + ~0UL == (pnltmp.hactive) || + ~0UL == (pnltmp.vactive) || + ~0UL == (pnltmp.bpp) || + ~0UL == (pnltmp.hfp) || + ~0UL == (pnltmp.hbp) || + ~0UL == (pnltmp.hsw) || + ~0UL == (pnltmp.vfp) || + ~0UL == (pnltmp.vbp) || + ~0UL == (pnltmp.vsw) || + ~0UL == (pnltmp.pxl_clk_div) || + ~0UL == (pnltmp.pol) || + ~0UL == (pnltmp.pup_delay) || + ~0UL == (pnltmp.pon_delay) + ) { + puts("lcd-settings in env/dtb incomplete!\n"); + printf("display-timings:\n" + "================\n" + "hactive: %d\n" + "vactive: %d\n" + "bpp : %d\n" + "hfp : %d\n" + "hbp : %d\n" + "hsw : %d\n" + "vfp : %d\n" + "vbp : %d\n" + "vsw : %d\n" + "pxlclk : %d\n" + "pol : 0x%08x\n" + "pondly : %d\n", + pnltmp.hactive, pnltmp.vactive, pnltmp.bpp, + pnltmp.hfp, pnltmp.hbp, pnltmp.hsw, + pnltmp.vfp, pnltmp.vbp, pnltmp.vsw, + pnltmp.pxl_clk_div, pnltmp.pol, pnltmp.pon_delay); + + return -1; + } + debug("lcd-settings in env complete, taking over.\n"); + memcpy((void *)panel, + (void *)&pnltmp, + sizeof(struct am335x_lcdpanel)); + + return 0; +} + +#ifdef CONFIG_USE_FDT +static int load_devicetree(void) +{ + char *dtbname = getenv("dtb"); + char *dtbdev = getenv("dtbdev"); + char *dtppart = getenv("dtbpart"); + u32 dtbaddr = getenv_ulong("dtbaddr", 16, ~0UL); + loff_t dtbsize; + + if (!dtbdev || !dtbdev) { + puts("load_devicetree: / missing.\n"); + return -1; + } + + if (fs_set_blk_dev(dtbdev, dtppart, FS_TYPE_EXT)) { + puts("load_devicetree: set_blk_dev failed.\n"); + return -1; + } + if (dtbname && dtbaddr != ~0UL) { + if (fs_read(dtbname, dtbaddr, 0, 0, &dtbsize) == 0) { + gd->fdt_blob = (void *)dtbaddr; + gd->fdt_size = dtbsize; + debug("loaded %d bytes of dtb onto 0x%08x\n", + (u32)dtbsize, dtbaddr); + return dtbsize; + } + puts("load_devicetree: load dtb failed,file does not exist!\n"); + } + + puts("load_devicetree: / missing!\n"); + return -1; +} + +static const char *dtbmacaddr(u32 ifno) +{ + int node, len; + char enet[16]; + const char *mac; + const char *path; + u32 dtbaddr = getenv_ulong("dtbaddr", 16, ~0UL); + + if (dtbaddr == ~0UL) { + puts("dtbmacaddr: failed to get 'dtbaddr' from env!\n"); + return NULL; + } + + node = fdt_path_offset((void *)dtbaddr, "/aliases"); + if (node < 0) + return NULL; + + sprintf(enet, "ethernet%d", ifno); + path = fdt_getprop((void *)dtbaddr, node, enet, NULL); + if (!path) { + printf("no alias for %s\n", enet); + return NULL; + } + + node = fdt_path_offset((void *)dtbaddr, path); + mac = fdt_getprop((void *)dtbaddr, node, "mac-address", &len); + if (mac && is_valid_ether_addr((u8 *)mac)) + return mac; + + return NULL; +} + +static void br_summaryscreen_printdtb(char *prefix, + char *name, + char *suffix) +{ + u32 dtbaddr = getenv_ulong("dtbaddr", 16, ~0UL); + char buf[32] = { 0 }; + const char *nodep = buf; + char *mac = 0; + int nodeoffset; + int len; + + if (dtbaddr == ~0UL) { + puts("br_summaryscreen: failed to get 'dtbaddr' from env!\n"); + return; + } + + if (strcmp(name, "brmac1") == 0) { + mac = (char *)dtbmacaddr(0); + if (mac) + sprintf(buf, "%pM", mac); + } else if (strcmp(name, "brmac2") == 0) { + mac = (char *)dtbmacaddr(1); + if (mac) + sprintf(buf, "%pM", mac); + } else { + nodeoffset = fdt_path_offset((void *)dtbaddr, + "/factory-settings"); + if (nodeoffset < 0) { + puts("no 'factory-settings' in dtb!\n"); + return; + } + nodep = fdt_getprop((void *)dtbaddr, nodeoffset, name, &len); + } + if (nodep && strlen(nodep) > 1) + lcd_printf("%s %s %s", prefix, nodep, suffix); + else + lcd_printf("\n"); +} +int ft_board_setup(void *blob, bd_t *bd) +{ + int nodeoffset; + + nodeoffset = fdt_path_offset(blob, "/factory-settings"); + if (nodeoffset < 0) { + puts("set bootloader version 'factory-settings' not in dtb!\n"); + return -1; + } + if (fdt_setprop(blob, nodeoffset, "bl-version", + PLAIN_VERSION, strlen(PLAIN_VERSION)) != 0) { + puts("set bootloader version 'bl-version' prop. not in dtb!\n"); + return -1; + } + return 0; +} +#else + +static void br_summaryscreen_printenv(char *prefix, + char *name, char *altname, + char *suffix) +{ + char *envval = getenv(name); + if (0 != envval) { + lcd_printf("%s %s %s", prefix, envval, suffix); + } else if (0 != altname) { + envval = getenv(altname); + if (0 != envval) + lcd_printf("%s %s %s", prefix, envval, suffix); + } else { + lcd_printf("\n"); + } +} +#endif +void br_summaryscreen(void) +{ +#ifdef CONFIG_USE_FDT + br_summaryscreen_printdtb(" - B&R -", "order-no", "-\n"); + br_summaryscreen_printdtb(" Serial/Rev :", "serial-no", " /"); + br_summaryscreen_printdtb(" ", "hw-revision", "\n"); + br_summaryscreen_printdtb(" MAC (IF1) :", "brmac1", "\n"); + br_summaryscreen_printdtb(" MAC (IF2) :", "brmac2", "\n"); + lcd_puts(" Bootloader : " PLAIN_VERSION "\n"); + lcd_puts("\n"); +#else + br_summaryscreen_printenv(" - B&R -", "br_orderno", 0, "-\n"); + br_summaryscreen_printenv(" Serial/Rev :", "br_serial", 0, "\n"); + br_summaryscreen_printenv(" MAC (IF1) :", "br_mac1", "ethaddr", "\n"); + br_summaryscreen_printenv(" MAC (IF2) :", "br_mac2", 0, "\n"); + lcd_puts(" Bootloader : " PLAIN_VERSION "\n"); + lcd_puts("\n"); +#endif +} + +void lcdpower(int on) +{ + u32 pin, swval, i; +#ifdef CONFIG_USE_FDT + u32 dtbaddr = getenv_ulong("dtbaddr", 16, ~0UL); + + if (dtbaddr == ~0UL) { + puts("lcdpower: failed to get 'dtbaddr' from env!\n"); + return; + } + pin = FDTPROP(dtbaddr, PATHINF, "pwrpin"); +#else + pin = getenv_ulong("ds1_pwr", 16, ~0UL); +#endif + if (pin == ~0UL) { + puts("no pwrpin in dtb/env, cannot powerup display!\n"); + return; + } + + for (i = 0; i < 3; i++) { + if (pin != 0) { + swval = pin & 0x80 ? 0 : 1; + if (on) + gpio_direction_output(pin & 0x7F, swval); + else + gpio_direction_output(pin & 0x7F, !swval); + + debug("switched pin %d to %d\n", pin & 0x7F, swval); + } + pin >>= 8; + } +} + +vidinfo_t panel_info = { + .vl_col = 1366, /* + * give full resolution for allocating enough + * memory + */ + .vl_row = 768, + .vl_bpix = 5, + .priv = 0 +}; + +void lcd_ctrl_init(void *lcdbase) +{ + struct am335x_lcdpanel lcd_panel; +#ifdef CONFIG_USE_FDT + /* TODO: is there a better place to load the dtb ? */ + load_devicetree(); +#endif + memset(&lcd_panel, 0, sizeof(struct am335x_lcdpanel)); + if (load_lcdtiming(&lcd_panel) != 0) + return; + + lcd_panel.panel_power_ctrl = &lcdpower; + + if (0 != am335xfb_init(&lcd_panel)) + printf("ERROR: failed to initialize video!"); + /* + * modifiy panel info to 'real' resolution, to operate correct with + * lcd-framework. + */ + panel_info.vl_col = lcd_panel.hactive; + panel_info.vl_row = lcd_panel.vactive; + + lcd_set_flush_dcache(1); +} + +void lcd_enable(void) +{ +#ifdef CONFIG_USE_FDT + u32 dtbaddr = getenv_ulong("dtbaddr", 16, ~0UL); + + if (dtbaddr == ~0UL) { + puts("lcdpower: failed to get 'dtbaddr' from env!\n"); + return; + } + unsigned int driver = FDTPROP(dtbaddr, PATHINF, "brightdrv"); + unsigned int bright = FDTPROP(dtbaddr, PATHINF, "brightdef"); + unsigned int pwmfrq = FDTPROP(dtbaddr, PATHINF, "brightfdim"); +#else + unsigned int driver = getenv_ulong("ds1_bright_drv", 16, 0UL); + unsigned int bright = getenv_ulong("ds1_bright_def", 10, 50); + unsigned int pwmfrq = getenv_ulong("ds1_pwmfreq", 10, ~0UL); +#endif + unsigned int tmp; + struct gptimer *const timerhw = (struct gptimer *)DM_TIMER6_BASE; + + bright = bright != ~0UL ? bright : 50; + + switch (driver) { + case 0: /* PMIC LED-Driver */ + /* brightness level */ + tps65217_reg_write(TPS65217_PROT_LEVEL_NONE, + TPS65217_WLEDCTRL2, bright, 0xFF); + /* turn on light */ + tps65217_reg_write(TPS65217_PROT_LEVEL_NONE, + TPS65217_WLEDCTRL1, 0x0A, 0xFF); + break; + case 1: /* PWM using timer6 */ + if (pwmfrq != ~0UL) { + timerhw->tiocp_cfg = TCFG_RESET; + udelay(10); + while (timerhw->tiocp_cfg & TCFG_RESET) + ; + tmp = ~0UL-(V_OSCK/pwmfrq); /* bottom value */ + timerhw->tldr = tmp; + timerhw->tcrr = tmp; + tmp = tmp + ((V_OSCK/pwmfrq)/100) * bright; + timerhw->tmar = tmp; + timerhw->tclr = (TCLR_PT | (2 << TCLR_TRG_SHIFT) | + TCLR_CE | TCLR_AR | TCLR_ST); + } else { + puts("invalid pwmfrq in env/dtb! skip PWM-setup.\n"); + } + break; + default: + puts("no suitable backlightdriver in env/dtb!\n"); + break; + } + br_summaryscreen(); +} +#elif CONFIG_SPL_BUILD +#else +#error "LCD-support with a suitable FB-Driver is mandatory !" +#endif /* CONFIG_LCD */ + void blink(u32 blinks, u32 intervall, u32 pin) { gpio_direction_output(pin, 0); @@ -43,6 +454,7 @@ void blink(u32 blinks, u32 intervall, u32 pin) gpio_set_value(pin, 0); } + #ifdef CONFIG_SPL_BUILD void pmicsetup(u32 mpupll) { @@ -115,6 +527,9 @@ void pmicsetup(u32 mpupll) /* Set MPU Frequency to what we detected now that voltages are set */ do_setup_dpll(&dpll_mpu_regs, &dpll_mpu_opp100); + /* Set PWR_EN bit in Status Register */ + tps65217_reg_write(TPS65217_PROT_LEVEL_NONE, + TPS65217_STATUS, TPS65217_PWR_OFF, TPS65217_PWR_OFF); } void set_uart_mux_conf(void) -- cgit v1.1