Module Name: src Committed By: jmcneill Date: Sun Mar 22 13:53:33 UTC 2015
Modified Files: src/sys/arch/arm/amlogic: amlogic_genfb.c amlogic_vpureg.h src/sys/arch/evbarm/amlogic: amlogic_machdep.c Log Message: Use the hardware scaler to do overscan compensation. You can set the scaling value as a percentage in two ways -- either as a kernel cmdline parameter (fb.scale=<pct>) or at runtime with sysctl (hw.genfb0.scale=<pct>). Setting scale=100 disables the scaler, any other value enables it. For the cheap TV on my desk, scale=95 gives me a fully visible framebuffer. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/amlogic/amlogic_genfb.c \ src/sys/arch/arm/amlogic/amlogic_vpureg.h cvs rdiff -u -r1.17 -r1.18 src/sys/arch/evbarm/amlogic/amlogic_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/amlogic/amlogic_genfb.c diff -u src/sys/arch/arm/amlogic/amlogic_genfb.c:1.1 src/sys/arch/arm/amlogic/amlogic_genfb.c:1.2 --- src/sys/arch/arm/amlogic/amlogic_genfb.c:1.1 Sat Mar 21 01:17:00 2015 +++ src/sys/arch/arm/amlogic/amlogic_genfb.c Sun Mar 22 13:53:33 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: amlogic_genfb.c,v 1.1 2015/03/21 01:17:00 jmcneill Exp $ */ +/* $NetBSD: amlogic_genfb.c,v 1.2 2015/03/22 13:53:33 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: amlogic_genfb.c,v 1.1 2015/03/21 01:17:00 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: amlogic_genfb.c,v 1.2 2015/03/22 13:53:33 jmcneill Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -40,6 +40,7 @@ __KERNEL_RCSID(0, "$NetBSD: amlogic_genf #include <sys/conf.h> #include <sys/bus.h> #include <sys/kmem.h> +#include <sys/sysctl.h> #include <arm/amlogic/amlogic_reg.h> #include <arm/amlogic/amlogic_var.h> @@ -60,6 +61,10 @@ static const struct amlogic_genfb_vic2mo { 3, 720, 480 }, { 4, 1280, 720 }, { 5, 1920, 1080 }, + { 6, 720, 480 }, + { 7, 720, 480 }, + { 8, 720, 240 }, + { 9, 720, 240 }, { 16, 1920, 1080 }, { 17, 720, 576 }, { 18, 720, 576 }, @@ -75,17 +80,24 @@ static const struct amlogic_genfb_vic2mo struct amlogic_genfb_softc { struct genfb_softc sc_gen; bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; + bus_space_handle_t sc_cav_bsh; bus_space_handle_t sc_hdmi_bsh; bus_space_handle_t sc_vpu_bsh; bus_dma_tag_t sc_dmat; + kmutex_t sc_lock; + + u_int sc_scale; + bus_dma_segment_t sc_dmasegs[1]; bus_size_t sc_dmasize; bus_dmamap_t sc_dmamap; void *sc_dmap; uint32_t sc_wstype; + + struct sysctllog *sc_sysctllog; + int sc_node_scale; }; static int amlogic_genfb_match(device_t, cfdata_t, void *); @@ -95,9 +107,15 @@ static int amlogic_genfb_ioctl(void *, v static paddr_t amlogic_genfb_mmap(void *, void *, off_t, int); static bool amlogic_genfb_shutdown(device_t, int); -static void amlogic_genfb_probe(struct amlogic_genfb_softc *); +static void amlogic_genfb_canvas_config(struct amlogic_genfb_softc *); +static void amlogic_genfb_osd_config(struct amlogic_genfb_softc *); +static void amlogic_genfb_scaler_config(struct amlogic_genfb_softc *); + +static void amlogic_genfb_init(struct amlogic_genfb_softc *); static int amlogic_genfb_alloc_videomem(struct amlogic_genfb_softc *); +static int amlogic_genfb_scale_helper(SYSCTLFN_PROTO); + void amlogic_genfb_set_console_dev(device_t); void amlogic_genfb_ddb_trap_callback(int); @@ -131,6 +149,11 @@ amlogic_genfb_hdmi_write_4(struct amlogi #define VPU_WRITE(sc, reg, val) \ bus_space_write_4((sc)->sc_bst, (sc)->sc_vpu_bsh, (reg), (val)) +#define CAV_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_cav_bsh, (reg)) +#define CAV_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_cav_bsh, (reg), (val)) + static int amlogic_genfb_match(device_t parent, cfdata_t match, void *aux) { @@ -152,13 +175,14 @@ amlogic_genfb_attach(device_t parent, de sc->sc_bst = aio->aio_core_bst; sc->sc_dmat = aio->aio_dmat; bus_space_subregion(aio->aio_core_bst, aio->aio_bsh, - loc->loc_offset, loc->loc_size, &sc->sc_bsh); + loc->loc_offset, loc->loc_size, &sc->sc_cav_bsh); bus_space_subregion(aio->aio_core_bst, aio->aio_bsh, AMLOGIC_HDMI_OFFSET, AMLOGIC_HDMI_SIZE, &sc->sc_hdmi_bsh); bus_space_subregion(aio->aio_core_bst, aio->aio_bsh, AMLOGIC_VPU_OFFSET, AMLOGIC_VPU_SIZE, &sc->sc_vpu_bsh); + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); - amlogic_genfb_probe(sc); + amlogic_genfb_init(sc); sc->sc_wstype = WSDISPLAY_TYPE_MESON; prop_dictionary_get_bool(dict, "is_console", &is_console); @@ -236,40 +260,207 @@ amlogic_genfb_shutdown(device_t self, in } static void -amlogic_genfb_probe(struct amlogic_genfb_softc *sc) +amlogic_genfb_canvas_config(struct amlogic_genfb_softc *sc) { prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev); - u_int width = 0, height = 0, i; + const paddr_t pa = sc->sc_dmamap->dm_segs[0].ds_addr; uint32_t datal, datah, addr; - uint32_t w1, w2, w3, w4; - int error; + u_int width, height; - datal = bus_space_read_4(sc->sc_bst, sc->sc_bsh, DC_CAV_LUT_DATAL_REG); - datah = bus_space_read_4(sc->sc_bst, sc->sc_bsh, DC_CAV_LUT_DATAH_REG); - addr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, DC_CAV_LUT_ADDR_REG); - - w1 = VPU_READ(sc, VIU_OSD2_BLK0_CFG_W1_REG); - w2 = VPU_READ(sc, VIU_OSD2_BLK0_CFG_W2_REG); - w3 = VPU_READ(sc, VIU_OSD2_BLK0_CFG_W3_REG); - w4 = VPU_READ(sc, VIU_OSD2_BLK0_CFG_W4_REG); - -#if 0 - const u_int w = (__SHIFTOUT(datal, DC_CAV_LUT_DATAL_WIDTH_L) | - (__SHIFTOUT(datah, DC_CAV_LUT_DATAH_WIDTH_H) << 3)) << 3; - const u_int h = __SHIFTOUT(datah, DC_CAV_LUT_DATAH_HEIGHT); -#endif + prop_dictionary_get_uint32(cfg, "width", &width); + prop_dictionary_get_uint32(cfg, "height", &height); - /* VIC is in AVI InfoFrame PB4. */ - const uint32_t vic = HDMI_READ(sc, HDMITX_AVI_INFO_ADDR + 4) & 0x7f; + const uint32_t w = (width * 3) >> 3; + const uint32_t h = height; + + datal = CAV_READ(sc, DC_CAV_LUT_DATAL_REG); + datah = CAV_READ(sc, DC_CAV_LUT_DATAH_REG); + addr = CAV_READ(sc, DC_CAV_LUT_ADDR_REG); + + datal &= ~DC_CAV_LUT_DATAL_WIDTH_L; + datal |= __SHIFTIN(w & 7, DC_CAV_LUT_DATAL_WIDTH_L); + datal &= ~DC_CAV_LUT_DATAL_FBADDR; + datal |= __SHIFTIN(pa >> 3, DC_CAV_LUT_DATAL_FBADDR); + CAV_WRITE(sc, DC_CAV_LUT_DATAL_REG, datal); + + datah &= ~DC_CAV_LUT_DATAH_BLKMODE; + datah |= __SHIFTIN(DC_CAV_LUT_DATAH_BLKMODE_LINEAR, + DC_CAV_LUT_DATAH_BLKMODE); + datah &= ~DC_CAV_LUT_DATAH_WIDTH_H; + datah |= __SHIFTIN(w >> 3, DC_CAV_LUT_DATAH_WIDTH_H); + datah &= ~DC_CAV_LUT_DATAH_HEIGHT; + datah |= __SHIFTIN(h, DC_CAV_LUT_DATAH_HEIGHT); + CAV_WRITE(sc, DC_CAV_LUT_DATAH_REG, datah); + + addr |= DC_CAV_LUT_ADDR_WR_EN; + CAV_WRITE(sc, DC_CAV_LUT_ADDR_REG, addr); +} + +static void +amlogic_genfb_osd_config(struct amlogic_genfb_softc *sc) +{ + prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev); + uint32_t w0, w1, w2, w3, w4; + u_int width, height; + + prop_dictionary_get_uint32(cfg, "width", &width); + prop_dictionary_get_uint32(cfg, "height", &height); + w0 = VPU_READ(sc, VIU_OSD2_BLK0_CFG_W0_REG); + w0 &= ~VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE; + w0 |= __SHIFTIN(7, VIU_OSD_BLK_CFG_W0_OSD_BLK_MODE); + w0 |= VIU_OSD_BLK_CFG_W0_LITTLE_ENDIAN; + w0 &= ~VIU_OSD_BLK_CFG_W0_INTERP_CTRL; + w0 &= ~VIU_OSD_BLK_CFG_W0_INTERLACE_EN; + w0 |= VIU_OSD_BLK_CFG_W0_RGB_EN; + w0 &= ~VIU_OSD_BLK_CFG_W0_COLOR_MATRIX; + VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W0_REG, w0); + + w1 = __SHIFTIN(width - 1, VIU_OSD_BLK_CFG_W1_X_END) | + __SHIFTIN(0, VIU_OSD_BLK_CFG_W1_X_START); + w2 = __SHIFTIN(height - 1, VIU_OSD_BLK_CFG_W2_Y_END) | + __SHIFTIN(0, VIU_OSD_BLK_CFG_W2_Y_START); + w3 = __SHIFTIN(width - 1, VIU_OSD_BLK_CFG_W3_H_END) | + __SHIFTIN(0, VIU_OSD_BLK_CFG_W3_H_START); + w4 = __SHIFTIN(height - 1, VIU_OSD_BLK_CFG_W4_V_END) | + __SHIFTIN(0, VIU_OSD_BLK_CFG_W4_V_START); + + VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W1_REG, w1); + VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W2_REG, w2); + VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W3_REG, w3); + VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W4_REG, w4); +} + +static void +amlogic_genfb_scaler_config(struct amlogic_genfb_softc *sc) +{ + prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev); + uint32_t scctl, sci_wh, sco_h, sco_v, hsc, vsc, hps, vps, hip, vip; + u_int width, height; + + prop_dictionary_get_uint32(cfg, "width", &width); + prop_dictionary_get_uint32(cfg, "height", &height); + + const u_int scale = sc->sc_scale; + const u_int dst_w = (width * scale) / 100; + const u_int dst_h = (height * scale) / 100; + const u_int margin_w = (width - dst_w) / 2; + const u_int margin_h = (height - dst_h) / 2; + const bool interlace_p = false; /* TODO */ + const bool scale_p = scale != 100; + + VPU_WRITE(sc, VPP_OSD_SC_DUMMY_DATA_REG, 0x00808000); + + scctl = VPU_READ(sc, VPP_OSD_SC_CTRL0_REG); + scctl |= VPP_OSD_SC_CTRL0_OSD_SC_PATH_EN; + scctl &= ~VPP_OSD_SC_CTRL0_OSD_SC_SEL; + scctl |= __SHIFTIN(1, VPP_OSD_SC_CTRL0_OSD_SC_SEL); /* OSD2 */ + scctl &= ~VPP_OSD_SC_CTRL0_DEFAULT_ALPHA; + scctl |= __SHIFTIN(0, VPP_OSD_SC_CTRL0_DEFAULT_ALPHA); + VPU_WRITE(sc, VPP_OSD_SC_CTRL0_REG, scctl); + + sci_wh = __SHIFTIN(width - 1, VPP_OSD_SCI_WH_M1_WIDTH) | + __SHIFTIN(height - 1, VPP_OSD_SCI_WH_M1_HEIGHT); + sco_h = __SHIFTIN(margin_w, VPP_OSD_SCO_H_START) | + __SHIFTIN(width - margin_w - 1, VPP_OSD_SCO_H_END); + sco_v = __SHIFTIN(margin_h, VPP_OSD_SCO_V_START) | + __SHIFTIN(height - margin_h - 1, VPP_OSD_SCO_V_END); + + VPU_WRITE(sc, VPP_OSD_SCI_WH_M1_REG, sci_wh); + VPU_WRITE(sc, VPP_OSD_SCO_H_REG, sco_h); + VPU_WRITE(sc, VPP_OSD_SCO_V_REG, sco_v); + + /* horizontal scaling */ + hsc = VPU_READ(sc, VPP_OSD_HSC_CTRL0_REG); + if (scale_p) { + hsc &= ~VPP_OSD_HSC_CTRL0_BANK_LENGTH; + hsc |= __SHIFTIN(4, VPP_OSD_HSC_CTRL0_BANK_LENGTH); + hsc &= ~VPP_OSD_HSC_CTRL0_INI_RCV_NUM0; + hsc |= __SHIFTIN(4, VPP_OSD_HSC_CTRL0_INI_RCV_NUM0); + hsc &= ~VPP_OSD_HSC_CTRL0_RPT_P0_NUM0; + hsc |= __SHIFTIN(1, VPP_OSD_HSC_CTRL0_RPT_P0_NUM0); + hsc |= VPP_OSD_HSC_CTRL0_HSCALE_EN; + } else { + hsc &= ~VPP_OSD_HSC_CTRL0_HSCALE_EN; + } + VPU_WRITE(sc, VPP_OSD_HSC_CTRL0_REG, hsc); + + /* vertical scaling */ + vsc = VPU_READ(sc, VPP_OSD_VSC_CTRL0_REG); + if (scale_p) { + vsc &= ~VPP_OSD_VSC_CTRL0_BANK_LENGTH; + vsc |= __SHIFTIN(4, VPP_OSD_VSC_CTRL0_BANK_LENGTH); + vsc &= ~VPP_OSD_VSC_CTRL0_TOP_INI_RCV_NUM0; + vsc |= __SHIFTIN(4, VPP_OSD_VSC_CTRL0_TOP_INI_RCV_NUM0); + vsc &= ~VPP_OSD_VSC_CTRL0_TOP_RPT_P0_NUM0; + vsc |= __SHIFTIN(1, VPP_OSD_VSC_CTRL0_TOP_RPT_P0_NUM0); + vsc &= ~VPP_OSD_VSC_CTRL0_BOT_INI_RCV_NUM0; + vsc &= ~VPP_OSD_VSC_CTRL0_BOT_RPT_P0_NUM0; + vsc &= ~VPP_OSC_VSC_CTRL0_INTERLACE; + if (interlace_p) { + /* interlace */ + vsc |= VPP_OSC_VSC_CTRL0_INTERLACE; + vsc |= __SHIFTIN(6, VPP_OSD_VSC_CTRL0_BOT_INI_RCV_NUM0); + vsc |= __SHIFTIN(2, VPP_OSD_VSC_CTRL0_BOT_RPT_P0_NUM0); + } + vsc |= VPP_OSD_VSC_CTRL0_VSCALE_EN; + } else { + vsc &= ~VPP_OSD_VSC_CTRL0_VSCALE_EN; + } + VPU_WRITE(sc, VPP_OSD_VSC_CTRL0_REG, vsc); + + /* free scale enable */ + if (scale_p) { + const u_int hf_phase_step = ((width << 18) / dst_w) << 6; + const u_int vf_phase_step = ((height << 20) / dst_h) << 4; + const u_int bot_ini_phase = + interlace_p ? ((vf_phase_step / 2) >> 8) : 0; + + hps = VPU_READ(sc, VPP_OSD_HSC_PHASE_STEP_REG); + hps &= ~VPP_OSD_HSC_PHASE_STEP_FORMAT; + hps |= __SHIFTIN(hf_phase_step, VPP_OSD_HSC_PHASE_STEP_FORMAT); + VPU_WRITE(sc, VPP_OSD_HSC_PHASE_STEP_REG, hps); + + hip = VPU_READ(sc, VPP_OSD_HSC_INI_PHASE_REG); + hip &= ~VPP_OSD_HSC_INI_PHASE_1; + VPU_WRITE(sc, VPP_OSD_HSC_INI_PHASE_REG, hip); + + vps = VPU_READ(sc, VPP_OSD_VSC_PHASE_STEP_REG); + vps &= ~VPP_OSD_VSC_PHASE_STEP_FORMAT; + vps |= __SHIFTIN(hf_phase_step, VPP_OSD_VSC_PHASE_STEP_FORMAT); + VPU_WRITE(sc, VPP_OSD_VSC_PHASE_STEP_REG, vps); + + vip = VPU_READ(sc, VPP_OSD_VSC_INI_PHASE_REG); + vip &= ~VPP_OSD_VSC_INI_PHASE_1; + vip |= __SHIFTIN(0, VPP_OSD_VSC_INI_PHASE_1); + vip &= ~VPP_OSD_VSC_INI_PHASE_0; + vip |= __SHIFTIN(bot_ini_phase, VPP_OSD_VSC_INI_PHASE_0); + VPU_WRITE(sc, VPP_OSD_VSC_INI_PHASE_REG, vip); + } +} + +static void +amlogic_genfb_init(struct amlogic_genfb_softc *sc) +{ + prop_dictionary_t cfg = device_properties(sc->sc_gen.sc_dev); + const struct sysctlnode *node, *devnode; + u_int width = 0, height = 0, i, scale = 100; + int error; + + /* + * Firmware has (maybe) setup HDMI TX for us. Read the VIC from + * the HDMI AVI InfoFrame (bits 6:0 in PB4) and map that to a + * framebuffer geometry. + */ + const uint32_t vic = HDMI_READ(sc, HDMITX_AVI_INFO_ADDR + 4) & 0x7f; for (i = 0; i < __arraycount(amlogic_genfb_modes); i++) { if (amlogic_genfb_modes[i].vic == vic) { aprint_debug(" [HDMI VIC %d]", vic); width = amlogic_genfb_modes[i].width; height = amlogic_genfb_modes[i].height; + break; } } - if (width == 0 || height == 0) { aprint_error(" [UNSUPPORTED HDMI VIC %d]", vic); return; @@ -279,54 +470,91 @@ amlogic_genfb_probe(struct amlogic_genfb sc->sc_dmasize = (fbsize + 3) & ~3; error = amlogic_genfb_alloc_videomem(sc); - if (error == 0) { - const paddr_t pa = sc->sc_dmamap->dm_segs[0].ds_addr; - const uint32_t w = width * 3; - const uint32_t h = height; - - datal &= ~DC_CAV_LUT_DATAL_WIDTH_L; - datal |= __SHIFTIN(w >> 3, DC_CAV_LUT_DATAL_WIDTH_L); - datal &= ~DC_CAV_LUT_DATAL_FBADDR; - datal |= __SHIFTIN(pa >> 3, DC_CAV_LUT_DATAL_FBADDR); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, DC_CAV_LUT_DATAL_REG, - datal); - - datah &= ~DC_CAV_LUT_DATAH_BLKMODE; - datah |= __SHIFTIN(DC_CAV_LUT_DATAH_BLKMODE_LINEAR, - DC_CAV_LUT_DATAH_BLKMODE); - datah &= ~DC_CAV_LUT_DATAH_WIDTH_H; - datah |= __SHIFTIN(w >> 6, DC_CAV_LUT_DATAH_WIDTH_H); - datah &= ~DC_CAV_LUT_DATAH_HEIGHT; - datah |= __SHIFTIN(h, DC_CAV_LUT_DATAH_HEIGHT); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, DC_CAV_LUT_DATAH_REG, - datah); - - addr |= DC_CAV_LUT_ADDR_WR_EN; - bus_space_write_4(sc->sc_bst, sc->sc_bsh, DC_CAV_LUT_ADDR_REG, - addr); - - w1 = __SHIFTIN(width - 1, VIU_OSD_BLK_CFG_W1_X_END); - w2 = __SHIFTIN(height - 1, VIU_OSD_BLK_CFG_W2_Y_END); - w3 = __SHIFTIN(width - 1, VIU_OSD_BLK_CFG_W3_H_END); - w4 = __SHIFTIN(height - 1, VIU_OSD_BLK_CFG_W4_V_END); - - VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W1_REG, w1); - VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W2_REG, w2); - VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W3_REG, w3); - VPU_WRITE(sc, VIU_OSD2_BLK0_CFG_W4_REG, w4); - - prop_dictionary_set_uint32(cfg, "width", width); - prop_dictionary_set_uint32(cfg, "height", height); - prop_dictionary_set_uint8(cfg, "depth", 24); - prop_dictionary_set_uint16(cfg, "linebytes", width * 3); - prop_dictionary_set_uint32(cfg, "address", 0); - prop_dictionary_set_uint32(cfg, "virtual_address", - (uintptr_t)sc->sc_dmap); - } else { + if (error) { aprint_error_dev(sc->sc_gen.sc_dev, "failed to allocate %u bytes of video memory: %d\n", (u_int)sc->sc_dmasize, error); + return; + } + + prop_dictionary_get_uint32(cfg, "scale", &scale); + if (scale > 100) { + scale = 100; + } else if (scale < 10) { + scale = 10; } + sc->sc_scale = scale; + + prop_dictionary_set_uint32(cfg, "width", width); + prop_dictionary_set_uint32(cfg, "height", height); + prop_dictionary_set_uint8(cfg, "depth", 24); + prop_dictionary_set_uint16(cfg, "linebytes", width * 3); + prop_dictionary_set_uint32(cfg, "address", 0); + prop_dictionary_set_uint32(cfg, "virtual_address", + (uintptr_t)sc->sc_dmap); + + amlogic_genfb_canvas_config(sc); + amlogic_genfb_osd_config(sc); + amlogic_genfb_scaler_config(sc); + + /* sysctl setup */ + error = sysctl_createv(&sc->sc_sysctllog, 0, NULL, &node, + CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL, + NULL, 0, NULL, 0, CTL_HW, CTL_EOL); + if (error) + goto sysctl_failed; + error = sysctl_createv(&sc->sc_sysctllog, 0, &node, &devnode, + 0, CTLTYPE_NODE, device_xname(sc->sc_gen.sc_dev), NULL, + NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); + if (error) + goto sysctl_failed; + error = sysctl_createv(&sc->sc_sysctllog, 0, &devnode, &node, + CTLFLAG_READWRITE, CTLTYPE_INT, "scale", NULL, + amlogic_genfb_scale_helper, 0, (void *)sc, 0, + CTL_CREATE, CTL_EOL); + if (error) + goto sysctl_failed; + sc->sc_node_scale = node->sysctl_num; + + return; + +sysctl_failed: + aprint_error_dev(sc->sc_gen.sc_dev, + "couldn't create sysctl nodes (%d)\n", error); + sysctl_teardown(&sc->sc_sysctllog); +} + +static int +amlogic_genfb_scale_helper(SYSCTLFN_ARGS) +{ + struct amlogic_genfb_softc *sc; + struct sysctlnode node; + int scale, oldscale, error; + + node = *rnode; + sc = node.sysctl_data; + scale = oldscale = sc->sc_scale; + node.sysctl_data = &scale; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return error; + + if (scale > 100) { + scale = 100; + } else if (scale < 10) { + scale = 10; + } + + if (scale == oldscale) { + return 0; + } + + mutex_enter(&sc->sc_lock); + sc->sc_scale = scale; + amlogic_genfb_scaler_config(sc); + mutex_exit(&sc->sc_lock); + + return 0; } static int Index: src/sys/arch/arm/amlogic/amlogic_vpureg.h diff -u src/sys/arch/arm/amlogic/amlogic_vpureg.h:1.1 src/sys/arch/arm/amlogic/amlogic_vpureg.h:1.2 --- src/sys/arch/arm/amlogic/amlogic_vpureg.h:1.1 Sat Mar 21 01:17:00 2015 +++ src/sys/arch/arm/amlogic/amlogic_vpureg.h Sun Mar 22 13:53:33 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: amlogic_vpureg.h,v 1.1 2015/03/21 01:17:00 jmcneill Exp $ */ +/* $NetBSD: amlogic_vpureg.h,v 1.2 2015/03/22 13:53:33 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -38,6 +38,17 @@ #define VIU_OSD2_BLK0_CFG_W3_REG VPU_REG(0x1a3e) #define VIU_OSD2_BLK0_CFG_W4_REG VPU_REG(0x1a64) #define VPP_MISC_REG VPU_REG(0x1d26) +#define VPP_OSD_VSC_PHASE_STEP_REG VPU_REG(0x1dc0) +#define VPP_OSD_VSC_INI_PHASE_REG VPU_REG(0x1dc1) +#define VPP_OSD_VSC_CTRL0_REG VPU_REG(0x1dc2) +#define VPP_OSD_HSC_PHASE_STEP_REG VPU_REG(0x1dc3) +#define VPP_OSD_HSC_INI_PHASE_REG VPU_REG(0x1dc4) +#define VPP_OSD_HSC_CTRL0_REG VPU_REG(0x1dc5) +#define VPP_OSD_SC_DUMMY_DATA_REG VPU_REG(0x1dc7) +#define VPP_OSD_SC_CTRL0_REG VPU_REG(0x1dc8) +#define VPP_OSD_SCI_WH_M1_REG VPU_REG(0x1dc9) +#define VPP_OSD_SCO_H_REG VPU_REG(0x1dca) +#define VPP_OSD_SCO_V_REG VPU_REG(0x1dcb) #define VIU_OSD_CTRL_STAT_ENABLE __BIT(21) #define VIU_OSD_CTRL_STAT_BLK3_ENABLE __BIT(3) @@ -70,4 +81,43 @@ #define VPP_MISC_POSTBLEND __BIT(7) +#define VPP_OSD_VSC_PHASE_STEP_FORMAT __BITS(27,0) + +#define VPP_OSD_VSC_INI_PHASE_0 __BITS(31,16) +#define VPP_OSD_VSC_INI_PHASE_1 __BITS(15,0) + +#define VPP_OSD_VSC_CTRL0_VSCALE_EN __BIT(24) +#define VPP_OSC_VSC_CTRL0_INTERLACE __BIT(23) +#define VPP_OSD_VSC_CTRL0_BOT_RPT_P0_NUM0 __BITS(17,16) +#define VPP_OSD_VSC_CTRL0_BOT_INI_RCV_NUM0 __BITS(14,11) +#define VPP_OSD_VSC_CTRL0_TOP_RPT_P0_NUM0 __BITS(9,8) +#define VPP_OSD_VSC_CTRL0_TOP_INI_RCV_NUM0 __BITS(6,3) +#define VPP_OSD_VSC_CTRL0_BANK_LENGTH __BITS(2,0) + +#define VPP_OSD_HSC_PHASE_STEP_FORMAT __BITS(27,0) + +#define VPP_OSD_HSC_INI_PHASE_0 __BITS(31,16) +#define VPP_OSD_HSC_INI_PHASE_1 __BITS(15,0) + +#define VPP_OSD_HSC_CTRL0_HSCALE_EN __BIT(22) +#define VPP_OSD_HSC_CTRL0_RPT_P0_NUM0 __BITS(9,8) +#define VPP_OSD_HSC_CTRL0_INI_RCV_NUM0 __BITS(6,3) +#define VPP_OSD_HSC_CTRL0_BANK_LENGTH __BITS(2,0) + +#define VPP_OSD_SC_CTRL0_OSC_SC_DIN_OSD1_ALPHA_MODE __BIT(14) +#define VPP_OSD_SC_CTRL0_OSC_SC_DIN_OSD2_ALPHA_MODE __BIT(13) +#define VPP_OSD_SC_CTRL0_OSC_SC_ALPHA_MODE __BIT(12) +#define VPP_OSD_SC_CTRL0_DEFAULT_ALPHA __BITS(11,4) +#define VPP_OSD_SC_CTRL0_OSD_SC_PATH_EN __BIT(3) +#define VPP_OSD_SC_CTRL0_OSD_SC_SEL __BITS(1,0) + +#define VPP_OSD_SCI_WH_M1_WIDTH __BITS(28,16) +#define VPP_OSD_SCI_WH_M1_HEIGHT __BITS(12,0) + +#define VPP_OSD_SCO_H_START __BITS(28,16) +#define VPP_OSD_SCO_H_END __BITS(12,0) + +#define VPP_OSD_SCO_V_START __BITS(28,16) +#define VPP_OSD_SCO_V_END __BITS(12,0) + #endif /* _ARM_AMLOGIC_VPUREG_H */ Index: src/sys/arch/evbarm/amlogic/amlogic_machdep.c diff -u src/sys/arch/evbarm/amlogic/amlogic_machdep.c:1.17 src/sys/arch/evbarm/amlogic/amlogic_machdep.c:1.18 --- src/sys/arch/evbarm/amlogic/amlogic_machdep.c:1.17 Sat Mar 21 01:17:00 2015 +++ src/sys/arch/evbarm/amlogic/amlogic_machdep.c Sun Mar 22 13:53:33 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: amlogic_machdep.c,v 1.17 2015/03/21 01:17:00 jmcneill Exp $ */ +/* $NetBSD: amlogic_machdep.c,v 1.18 2015/03/22 13:53:33 jmcneill Exp $ */ /* * Machine dependent functions for kernel setup for TI OSK5912 board. @@ -125,7 +125,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: amlogic_machdep.c,v 1.17 2015/03/21 01:17:00 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: amlogic_machdep.c,v 1.18 2015/03/22 13:53:33 jmcneill Exp $"); #include "opt_machdep.h" #include "opt_ddb.h" @@ -545,6 +545,7 @@ amlogic_device_register(device_t self, v #if NGENFB > 0 if (device_is_a(self, "genfb")) { char *ptr; + int scale; amlogic_genfb_set_console_dev(self); #ifdef DDB db_trap_callback = amlogic_genfb_ddb_trap_callback; @@ -558,6 +559,10 @@ amlogic_device_register(device_t self, v } else { prop_dictionary_set_bool(dict, "is_console", false); } + if (get_bootconf_option(boot_args, "fb.scale", + BOOTOPT_TYPE_INT, &scale) && scale > 0) { + prop_dictionary_set_uint32(dict, "scale", scale); + } } #endif }