Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch Use the hardware scaler to do overscan compensation...
details: https://anonhg.NetBSD.org/src/rev/21db86b58f69
branches: trunk
changeset: 336827:21db86b58f69
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Sun Mar 22 13:53:33 2015 +0000
description:
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.
diffstat:
sys/arch/arm/amlogic/amlogic_genfb.c | 372 ++++++++++++++++++++++++-----
sys/arch/arm/amlogic/amlogic_vpureg.h | 52 ++++-
sys/arch/evbarm/amlogic/amlogic_machdep.c | 9 +-
3 files changed, 358 insertions(+), 75 deletions(-)
diffs (truncated from 583 to 300 lines):
diff -r da63d88b7bec -r 21db86b58f69 sys/arch/arm/amlogic/amlogic_genfb.c
--- a/sys/arch/arm/amlogic/amlogic_genfb.c Sun Mar 22 12:48:18 2015 +0000
+++ b/sys/arch/arm/amlogic/amlogic_genfb.c Sun Mar 22 13:53:33 2015 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -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 @@
#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 @@
{ 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 @@
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 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 @@
#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 @@
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 @@
}
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);
+ const paddr_t pa = sc->sc_dmamap->dm_segs[0].ds_addr;
+ uint32_t datal, datah, addr;
+ u_int width, height;
+
+ prop_dictionary_get_uint32(cfg, "width", &width);
+ prop_dictionary_get_uint32(cfg, "height", &height);
+
+ 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);
- u_int width = 0, height = 0, i;
- uint32_t datal, datah, addr;
- uint32_t w1, w2, w3, w4;
+ 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);
Home |
Main Index |
Thread Index |
Old Index