void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon, struct drm_display_mode *mode) { unsigned int bp, hsync, vsync; u8 clk_delay; u32 val; WARN_ON(!tcon->quirks->has_channel_1); /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 1); regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, SUN4I_TCON1_CTL_CLK_DELAY_MASK, SUN4I_TCON1_CTL_CLK_DELAY(clk_delay)); /* Set interlaced mode */ if (mode->flags & DRM_MODE_FLAG_INTERLACE) val = SUN4I_TCON1_CTL_INTERLACE_ENABLE; else val = 0; regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, SUN4I_TCON1_CTL_INTERLACE_ENABLE, val); /* Set the input resolution */ regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG, SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) | SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay)); /* Set the upscaling resolution */ regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG, SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) | SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay)); /* Set the output resolution */ regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG, SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) | SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay)); /* Set horizontal display timings */ bp = mode->crtc_htotal - mode->crtc_hsync_end; DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", mode->htotal, bp); regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG, SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) | SUN4I_TCON1_BASIC3_H_BACKPORCH(bp)); /* Set vertical display timings */ bp = mode->crtc_vtotal - mode->crtc_vsync_end; DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", mode->vtotal, bp); regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG, SUN4I_TCON1_BASIC4_V_TOTAL(mode->vtotal) | SUN4I_TCON1_BASIC4_V_BACKPORCH(bp)); /* Set Hsync and Vsync length */ hsync = mode->crtc_hsync_end - mode->crtc_hsync_start; vsync = mode->crtc_vsync_end - mode->crtc_vsync_start; DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync); regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG, SUN4I_TCON1_BASIC5_V_SYNC(vsync) | SUN4I_TCON1_BASIC5_H_SYNC(hsync)); /* Map output pins to channel 1 */ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, SUN4I_TCON_GCTL_IOMAP_MASK, SUN4I_TCON_GCTL_IOMAP_TCON1); /* * FIXME: Undocumented bits */ if (tcon->quirks->has_unknown_mux) regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, 1); }
static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon, const struct drm_display_mode *mode) { unsigned int bp, hsync, vsync, vtotal; u8 clk_delay; u32 val; WARN_ON(!tcon->quirks->has_channel_1); /* Configure the dot clock */ clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000); /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 1); regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, SUN4I_TCON1_CTL_CLK_DELAY_MASK, SUN4I_TCON1_CTL_CLK_DELAY(clk_delay)); /* Set interlaced mode */ if (mode->flags & DRM_MODE_FLAG_INTERLACE) val = SUN4I_TCON1_CTL_INTERLACE_ENABLE; else val = 0; regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, SUN4I_TCON1_CTL_INTERLACE_ENABLE, val); /* Set the input resolution */ regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG, SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) | SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay)); /* Set the upscaling resolution */ regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG, SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) | SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay)); /* Set the output resolution */ regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG, SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) | SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay)); /* Set horizontal display timings */ bp = mode->crtc_htotal - mode->crtc_hsync_start; DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", mode->htotal, bp); regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG, SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) | SUN4I_TCON1_BASIC3_H_BACKPORCH(bp)); bp = mode->crtc_vtotal - mode->crtc_vsync_start; DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", mode->crtc_vtotal, bp); /* * The vertical resolution needs to be doubled in all * cases. We could use crtc_vtotal and always multiply by two, * but that leads to a rounding error in interlace when vtotal * is odd. * * This happens with TV's PAL for example, where vtotal will * be 625, crtc_vtotal 312, and thus crtc_vtotal * 2 will be * 624, which apparently confuses the hardware. * * To work around this, we will always use vtotal, and * multiply by two only if we're not in interlace. */ vtotal = mode->vtotal; if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) vtotal = vtotal * 2; /* Set vertical display timings */ regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG, SUN4I_TCON1_BASIC4_V_TOTAL(vtotal) | SUN4I_TCON1_BASIC4_V_BACKPORCH(bp)); /* Set Hsync and Vsync length */ hsync = mode->crtc_hsync_end - mode->crtc_hsync_start; vsync = mode->crtc_vsync_end - mode->crtc_vsync_start; DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync); regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG, SUN4I_TCON1_BASIC5_V_SYNC(vsync) | SUN4I_TCON1_BASIC5_H_SYNC(hsync)); /* Map output pins to channel 1 */ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, SUN4I_TCON_GCTL_IOMAP_MASK, SUN4I_TCON_GCTL_IOMAP_TCON1); }
void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon, struct drm_display_mode *mode) { unsigned int bp, hsync, vsync; u8 clk_delay; u32 val = 0; /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 0); regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, SUN4I_TCON0_CTL_CLK_DELAY_MASK, SUN4I_TCON0_CTL_CLK_DELAY(clk_delay)); /* Set the resolution */ regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG, SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) | SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); /* * This is called a backporch in the register documentation, * but it really is the front porch + hsync */ bp = mode->crtc_htotal - mode->crtc_hsync_start; DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", mode->crtc_htotal, bp); /* Set horizontal display timings */ regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG, SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) | SUN4I_TCON0_BASIC1_H_BACKPORCH(bp)); /* * This is called a backporch in the register documentation, * but it really is the front porch + hsync */ bp = mode->crtc_vtotal - mode->crtc_vsync_start; DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", mode->crtc_vtotal, bp); /* Set vertical display timings */ regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG, SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal) | SUN4I_TCON0_BASIC2_V_BACKPORCH(bp)); /* Set Hsync and Vsync length */ hsync = mode->crtc_hsync_end - mode->crtc_hsync_start; vsync = mode->crtc_vsync_end - mode->crtc_vsync_start; DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync); regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG, SUN4I_TCON0_BASIC3_V_SYNC(vsync) | SUN4I_TCON0_BASIC3_H_SYNC(hsync)); /* Setup the polarity of the various signals */ if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE; if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, val); /* Map output pins to channel 0 */ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, SUN4I_TCON_GCTL_IOMAP_MASK, SUN4I_TCON_GCTL_IOMAP_TCON0); /* Enable the output on the pins */ regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0); }
static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, const struct drm_encoder *encoder, const struct drm_display_mode *mode) { unsigned int bp; u8 clk_delay; u32 reg, val = 0; tcon->dclk_min_div = 7; tcon->dclk_max_div = 7; sun4i_tcon0_mode_set_common(tcon, mode); /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 0); regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, SUN4I_TCON0_CTL_CLK_DELAY_MASK, SUN4I_TCON0_CTL_CLK_DELAY(clk_delay)); /* * This is called a backporch in the register documentation, * but it really is the back porch + hsync */ bp = mode->crtc_htotal - mode->crtc_hsync_start; DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", mode->crtc_htotal, bp); /* Set horizontal display timings */ regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG, SUN4I_TCON0_BASIC1_H_TOTAL(mode->htotal) | SUN4I_TCON0_BASIC1_H_BACKPORCH(bp)); /* * This is called a backporch in the register documentation, * but it really is the back porch + hsync */ bp = mode->crtc_vtotal - mode->crtc_vsync_start; DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", mode->crtc_vtotal, bp); /* Set vertical display timings */ regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG, SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) | SUN4I_TCON0_BASIC2_V_BACKPORCH(bp)); reg = SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0 | SUN4I_TCON0_LVDS_IF_DATA_POL_NORMAL | SUN4I_TCON0_LVDS_IF_CLK_POL_NORMAL; if (sun4i_tcon_get_pixel_depth(encoder) == 24) reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS; else reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS; regmap_write(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, reg); /* Setup the polarity of the various signals */ if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE; if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val); /* Map output pins to channel 0 */ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, SUN4I_TCON_GCTL_IOMAP_MASK, SUN4I_TCON_GCTL_IOMAP_TCON0); }