mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-26 20:44:32 +08:00
Armada DRM updates:
- Fix interlace support. - use __drm_atomic_helper_plane_reset in overlay reset. - since the overlay and video planes use essentially the same format registers, precompute their values while validating. - fix a long-standing deficiency with overlay planes and interlace modes - calculate plane starting address at atomic_check stage rather than when we're programming the registers. - add gamma support. - ensure mode adjustments made by other components are properly handled in the driver and applied to the CRTC-programmed mode. - add and use register definitions for the "REG4F" register. - use drm_atomic_helper_shutdown() when tearing down to ensure that the hardware is properly shutdown. - add CRTC-level mode validation to ensure that we don't allow a mode that the CRTC-level hardware can not support. - improve the clocking selection for Armada 510 support. - move CRTC debugfs files into the crtc-specific directory, using the DRM helper to create these files. - patch from Lubomir Rintel to replace a simple framebuffer. - use the OF graph walker rather than open-coding this. - eliminate a useless check for the availability of the remote's parent which isn't required. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIVAwUAXRsdkfTnkBvkraxkAQKl/w//ai5bPyto6CwwkhNfmfFV53Y7fuii8Pbv aSuzziNGRjMJd7bQLb618QM7wcof7FzlEfPlHveZhQr0Pg8/FFza9C8Hk+Lwin1h bJzUWbyShsAVK6ZxHTxHVA94Ww4GNR9UayPQYn+R31BzDHv4maTJYwrz6TvhIPiW yKLhQDsq9X8/MjRyiK7pbYqzVPAP+VEt6Kw7CI/Xyvq3iNZWPqgvSRLwsEze04Jk CGqJE3+1NmgdOhOhEuCLWwSpk0U798AP5/39wpyGqHA1bmfWVK+kaVSakeUXYqe0 MmGCC/N79ibVCS74l09Bc7u6iGJiuoIg5K+Jis8LvxxWnKKfKiC0MXSmpRynwX6Y 9PIHwqXK2f7cSzTjxHdSgA8W/HKFs9Sn0nIm2trjVoqbVIaTOddK1Ej3dcL2eqD6 3EtdDhhsXFNMFkR6FdXKyhxSccVyt/4u9xeE7kTB0oo+n7bfE9YDNXGWpMn+9Tvp oSoSYG4flRusar/6KfItSItNE5Pg4T6syFnY1P0dxYyUTr3KP9MPLMXcBKFIsk1Z B+5jzvkpw5VkegYJKp7qYKs5CLjYINk7T0x4JLysE/2lb4LfBnMyDfEiFjILCCVU zaXo4TwiaThExblbKWoxuN7fnGr4Soxfv9tJng3iY7DVoPe817N6b9A7BRn7NjWJ 7CvgY9uIXoA= =+Fy+ -----END PGP SIGNATURE----- Merge tag 'for-airlie-armada' of git://git.armlinux.org.uk/~rmk/linux-arm into drm-next Armada DRM updates: - Fix interlace support. - use __drm_atomic_helper_plane_reset in overlay reset. - since the overlay and video planes use essentially the same format registers, precompute their values while validating. - fix a long-standing deficiency with overlay planes and interlace modes - calculate plane starting address at atomic_check stage rather than when we're programming the registers. - add gamma support. - ensure mode adjustments made by other components are properly handled in the driver and applied to the CRTC-programmed mode. - add and use register definitions for the "REG4F" register. - use drm_atomic_helper_shutdown() when tearing down to ensure that the hardware is properly shutdown. - add CRTC-level mode validation to ensure that we don't allow a mode that the CRTC-level hardware can not support. - improve the clocking selection for Armada 510 support. - move CRTC debugfs files into the crtc-specific directory, using the DRM helper to create these files. - patch from Lubomir Rintel to replace a simple framebuffer. - use the OF graph walker rather than open-coding this. - eliminate a useless check for the availability of the remote's parent which isn't required. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Russell King <rmk@armlinux.org.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20190702091313.GA23442@rmk-PC.armlinux.org.uk
This commit is contained in:
commit
f07b56e7d0
@ -14,18 +14,62 @@
|
||||
#include "armada_drm.h"
|
||||
#include "armada_hw.h"
|
||||
|
||||
struct armada510_variant_data {
|
||||
struct clk *clks[4];
|
||||
struct clk *sel_clk;
|
||||
};
|
||||
|
||||
static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
|
||||
{
|
||||
struct armada510_variant_data *v;
|
||||
struct clk *clk;
|
||||
int idx;
|
||||
|
||||
clk = devm_clk_get(dev, "ext_ref_clk1");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk);
|
||||
v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
dcrtc->extclk[0] = clk;
|
||||
dcrtc->variant_data = v;
|
||||
|
||||
/* Lower the watermark so to eliminate jitter at higher bandwidths */
|
||||
armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F);
|
||||
if (dev->of_node) {
|
||||
struct property *prop;
|
||||
const char *s;
|
||||
|
||||
of_property_for_each_string(dev->of_node, "clock-names", prop,
|
||||
s) {
|
||||
if (!strcmp(s, "ext_ref_clk0"))
|
||||
idx = 0;
|
||||
else if (!strcmp(s, "ext_ref_clk1"))
|
||||
idx = 1;
|
||||
else if (!strcmp(s, "plldivider"))
|
||||
idx = 2;
|
||||
else if (!strcmp(s, "axibus"))
|
||||
idx = 3;
|
||||
else
|
||||
continue;
|
||||
|
||||
clk = devm_clk_get(dev, s);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
|
||||
PTR_ERR(clk);
|
||||
v->clks[idx] = clk;
|
||||
}
|
||||
} else {
|
||||
clk = devm_clk_get(dev, "ext_ref_clk1");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
|
||||
PTR_ERR(clk);
|
||||
|
||||
v->clks[1] = clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lower the watermark so to eliminate jitter at higher bandwidths.
|
||||
* Disable SRAM read wait state to avoid system hang with external
|
||||
* clock.
|
||||
*/
|
||||
armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK,
|
||||
dcrtc->base + LCD_CFG_RDREG4F);
|
||||
|
||||
/* Initialise SPU register */
|
||||
writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
|
||||
@ -34,65 +78,77 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u32 armada510_clk_sels[] = {
|
||||
SCLK_510_EXTCLK0,
|
||||
SCLK_510_EXTCLK1,
|
||||
SCLK_510_PLL,
|
||||
SCLK_510_AXI,
|
||||
};
|
||||
|
||||
static const struct armada_clocking_params armada510_clocking = {
|
||||
/* HDMI requires -0.6%..+0.5% */
|
||||
.permillage_min = 994,
|
||||
.permillage_max = 1005,
|
||||
.settable = BIT(0) | BIT(1),
|
||||
.div_max = SCLK_510_INT_DIV_MASK,
|
||||
};
|
||||
|
||||
/*
|
||||
* Armada510 specific SCLK register selection.
|
||||
* This gets called with sclk = NULL to test whether the mode is
|
||||
* supportable, and again with sclk != NULL to set the clocks up for
|
||||
* that. The former can return an error, but the latter is expected
|
||||
* not to.
|
||||
*
|
||||
* We currently are pretty rudimentary here, always selecting
|
||||
* EXT_REF_CLK_1 for LCD0 and erroring LCD1. This needs improvement!
|
||||
*/
|
||||
static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
|
||||
const struct drm_display_mode *mode, uint32_t *sclk)
|
||||
{
|
||||
struct clk *clk = dcrtc->extclk[0];
|
||||
int ret;
|
||||
struct armada510_variant_data *v = dcrtc->variant_data;
|
||||
unsigned long desired_khz = mode->crtc_clock;
|
||||
struct armada_clk_result res;
|
||||
int ret, idx;
|
||||
|
||||
if (dcrtc->num == 1)
|
||||
return -EINVAL;
|
||||
idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking,
|
||||
v->clks, ARRAY_SIZE(v->clks),
|
||||
desired_khz);
|
||||
if (idx < 0)
|
||||
return idx;
|
||||
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
if (dcrtc->clk != clk) {
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
dcrtc->clk = clk;
|
||||
}
|
||||
ret = clk_prepare_enable(res.clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sclk) {
|
||||
uint32_t rate, ref, div;
|
||||
clk_set_rate(res.clk, res.desired_clk_hz);
|
||||
|
||||
rate = mode->clock * 1000;
|
||||
ref = clk_round_rate(clk, rate);
|
||||
div = DIV_ROUND_UP(ref, rate);
|
||||
if (div < 1)
|
||||
div = 1;
|
||||
*sclk = res.div | armada510_clk_sels[idx];
|
||||
|
||||
clk_set_rate(clk, ref);
|
||||
*sclk = div | SCLK_510_EXTCLK1;
|
||||
/* We are now using this clock */
|
||||
v->sel_clk = res.clk;
|
||||
swap(dcrtc->clk, res.clk);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(res.clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void armada510_crtc_disable(struct armada_crtc *dcrtc)
|
||||
{
|
||||
if (!IS_ERR(dcrtc->clk)) {
|
||||
if (dcrtc->clk) {
|
||||
clk_disable_unprepare(dcrtc->clk);
|
||||
dcrtc->clk = ERR_PTR(-EINVAL);
|
||||
dcrtc->clk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void armada510_crtc_enable(struct armada_crtc *dcrtc,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
if (IS_ERR(dcrtc->clk)) {
|
||||
dcrtc->clk = dcrtc->extclk[0];
|
||||
WARN_ON(clk_prepare_enable(dcrtc->clk));
|
||||
struct armada510_variant_data *v = dcrtc->variant_data;
|
||||
|
||||
if (!dcrtc->clk && v->sel_clk) {
|
||||
if (!WARN_ON(clk_prepare_enable(v->sel_clk)))
|
||||
dcrtc->clk = v->sel_clk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,70 @@ static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc)
|
||||
}
|
||||
}
|
||||
|
||||
static void armada_drm_update_gamma(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_property_blob *blob = crtc->state->gamma_lut;
|
||||
void __iomem *base = drm_to_armada_crtc(crtc)->base;
|
||||
int i;
|
||||
|
||||
if (blob) {
|
||||
struct drm_color_lut *lut = blob->data;
|
||||
|
||||
armada_updatel(CFG_CSB_256x8, CFG_CSB_256x8 | CFG_PDWN256x8,
|
||||
base + LCD_SPU_SRAM_PARA1);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
writel_relaxed(drm_color_lut_extract(lut[i].red, 8),
|
||||
base + LCD_SPU_SRAM_WRDAT);
|
||||
writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_YR,
|
||||
base + LCD_SPU_SRAM_CTRL);
|
||||
readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
|
||||
writel_relaxed(drm_color_lut_extract(lut[i].green, 8),
|
||||
base + LCD_SPU_SRAM_WRDAT);
|
||||
writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_UG,
|
||||
base + LCD_SPU_SRAM_CTRL);
|
||||
readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
|
||||
writel_relaxed(drm_color_lut_extract(lut[i].blue, 8),
|
||||
base + LCD_SPU_SRAM_WRDAT);
|
||||
writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_VB,
|
||||
base + LCD_SPU_SRAM_CTRL);
|
||||
readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
|
||||
}
|
||||
armada_updatel(CFG_GAMMA_ENA, CFG_GAMMA_ENA,
|
||||
base + LCD_SPU_DMA_CTRL0);
|
||||
} else {
|
||||
armada_updatel(0, CFG_GAMMA_ENA, base + LCD_SPU_DMA_CTRL0);
|
||||
armada_updatel(CFG_PDWN256x8, CFG_CSB_256x8 | CFG_PDWN256x8,
|
||||
base + LCD_SPU_SRAM_PARA1);
|
||||
}
|
||||
}
|
||||
|
||||
static enum drm_mode_status armada_drm_crtc_mode_valid(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
|
||||
|
||||
if (mode->vscan > 1)
|
||||
return MODE_NO_VSCAN;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_HSKEW)
|
||||
return MODE_H_ILLEGAL;
|
||||
|
||||
/* We can't do interlaced modes if we don't have the SPU_ADV_REG */
|
||||
if (!dcrtc->variant->has_spu_adv_reg &&
|
||||
mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
return MODE_NO_INTERLACE;
|
||||
|
||||
if (mode->flags & (DRM_MODE_FLAG_BCAST | DRM_MODE_FLAG_PIXMUX |
|
||||
DRM_MODE_FLAG_CLKDIV2))
|
||||
return MODE_BAD;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
/* The mode_config.mutex will be held for this call */
|
||||
static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode, struct drm_display_mode *adj)
|
||||
@ -137,9 +201,18 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
|
||||
int ret;
|
||||
|
||||
/* We can't do interlaced modes if we don't have the SPU_ADV_REG */
|
||||
if (!dcrtc->variant->has_spu_adv_reg &&
|
||||
adj->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
/*
|
||||
* Set CRTC modesetting parameters for the adjusted mode. This is
|
||||
* applied after the connectors, bridges, and encoders have fixed up
|
||||
* this mode, as described above drm_atomic_helper_check_modeset().
|
||||
*/
|
||||
drm_mode_set_crtcinfo(adj, CRTC_INTERLACE_HALVE_V);
|
||||
|
||||
/*
|
||||
* Validate the adjusted mode in case an encoder/bridge has set
|
||||
* something we don't support.
|
||||
*/
|
||||
if (armada_drm_crtc_mode_valid(crtc, adj) != MODE_OK)
|
||||
return false;
|
||||
|
||||
/* Check whether the display mode is possible */
|
||||
@ -278,16 +351,9 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
|
||||
armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV);
|
||||
|
||||
if (interlaced ^ dcrtc->interlaced) {
|
||||
if (adj->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
drm_crtc_vblank_get(&dcrtc->crtc);
|
||||
else
|
||||
drm_crtc_vblank_put(&dcrtc->crtc);
|
||||
dcrtc->interlaced = interlaced;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dcrtc->irq_lock, flags);
|
||||
|
||||
dcrtc->interlaced = interlaced;
|
||||
/* Even interlaced/progressive frame */
|
||||
dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 |
|
||||
adj->crtc_htotal;
|
||||
@ -345,6 +411,20 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
|
||||
}
|
||||
|
||||
static int armada_drm_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
|
||||
|
||||
if (state->gamma_lut && drm_color_lut_size(state->gamma_lut) != 256)
|
||||
return -EINVAL;
|
||||
|
||||
if (state->color_mgmt_changed)
|
||||
state->planes_changed = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
@ -352,6 +432,9 @@ static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
|
||||
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
|
||||
|
||||
if (crtc->state->color_mgmt_changed)
|
||||
armada_drm_update_gamma(crtc);
|
||||
|
||||
dcrtc->regs_idx = 0;
|
||||
dcrtc->regs = dcrtc->atomic_regs;
|
||||
}
|
||||
@ -390,6 +473,9 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
|
||||
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
|
||||
|
||||
if (old_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
|
||||
drm_crtc_vblank_put(crtc);
|
||||
|
||||
drm_crtc_vblank_off(crtc);
|
||||
armada_drm_crtc_update(dcrtc, false);
|
||||
|
||||
@ -434,12 +520,17 @@ static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
armada_drm_crtc_update(dcrtc, true);
|
||||
drm_crtc_vblank_on(crtc);
|
||||
|
||||
if (crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
|
||||
WARN_ON(drm_crtc_vblank_get(crtc));
|
||||
|
||||
armada_drm_crtc_queue_state_event(crtc);
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
|
||||
.mode_valid = armada_drm_crtc_mode_valid,
|
||||
.mode_fixup = armada_drm_crtc_mode_fixup,
|
||||
.mode_set_nofb = armada_drm_crtc_mode_set_nofb,
|
||||
.atomic_check = armada_drm_crtc_atomic_check,
|
||||
.atomic_begin = armada_drm_crtc_atomic_begin,
|
||||
.atomic_flush = armada_drm_crtc_atomic_flush,
|
||||
.atomic_disable = armada_drm_crtc_atomic_disable,
|
||||
@ -460,6 +551,13 @@ static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,
|
||||
for (x = 0; x < width; x++, p++) {
|
||||
uint32_t val = *p;
|
||||
|
||||
/*
|
||||
* In "ARGB888" (HWC32) mode, writing to the SRAM
|
||||
* requires these bits to contain:
|
||||
* 31:24 = alpha 23:16 = blue 15:8 = green 7:0 = red
|
||||
* So, it's actually ABGR8888. This is independent
|
||||
* of the SWAPRB bits in DMA control register 0.
|
||||
*/
|
||||
val = (val & 0xff00ff00) |
|
||||
(val & 0x000000ff) << 16 |
|
||||
(val & 0x00ff0000) >> 16;
|
||||
@ -676,6 +774,14 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
|
||||
kfree(dcrtc);
|
||||
}
|
||||
|
||||
static int armada_drm_crtc_late_register(struct drm_crtc *crtc)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
armada_drm_crtc_debugfs_init(drm_to_armada_crtc(crtc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These are called under the vbl_lock. */
|
||||
static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
@ -703,14 +809,93 @@ static const struct drm_crtc_funcs armada_crtc_funcs = {
|
||||
.cursor_set = armada_drm_crtc_cursor_set,
|
||||
.cursor_move = armada_drm_crtc_cursor_move,
|
||||
.destroy = armada_drm_crtc_destroy,
|
||||
.gamma_set = drm_atomic_helper_legacy_gamma_set,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.late_register = armada_drm_crtc_late_register,
|
||||
.enable_vblank = armada_drm_crtc_enable_vblank,
|
||||
.disable_vblank = armada_drm_crtc_disable_vblank,
|
||||
};
|
||||
|
||||
int armada_crtc_select_clock(struct armada_crtc *dcrtc,
|
||||
struct armada_clk_result *res,
|
||||
const struct armada_clocking_params *params,
|
||||
struct clk *clks[], size_t num_clks,
|
||||
unsigned long desired_khz)
|
||||
{
|
||||
unsigned long desired_hz = desired_khz * 1000;
|
||||
unsigned long desired_clk_hz; // requested clk input
|
||||
unsigned long real_clk_hz; // actual clk input
|
||||
unsigned long real_hz; // actual pixel clk
|
||||
unsigned long permillage;
|
||||
struct clk *clk;
|
||||
u32 div;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG_KMS("[CRTC:%u:%s] desired clock=%luHz\n",
|
||||
dcrtc->crtc.base.id, dcrtc->crtc.name, desired_hz);
|
||||
|
||||
for (i = 0; i < num_clks; i++) {
|
||||
clk = clks[i];
|
||||
if (!clk)
|
||||
continue;
|
||||
|
||||
if (params->settable & BIT(i)) {
|
||||
real_clk_hz = clk_round_rate(clk, desired_hz);
|
||||
desired_clk_hz = desired_hz;
|
||||
} else {
|
||||
real_clk_hz = clk_get_rate(clk);
|
||||
desired_clk_hz = real_clk_hz;
|
||||
}
|
||||
|
||||
/* If the clock can do exactly the desired rate, we're done */
|
||||
if (real_clk_hz == desired_hz) {
|
||||
real_hz = real_clk_hz;
|
||||
div = 1;
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Calculate the divider - if invalid, we can't do this rate */
|
||||
div = DIV_ROUND_CLOSEST(real_clk_hz, desired_hz);
|
||||
if (div == 0 || div > params->div_max)
|
||||
continue;
|
||||
|
||||
/* Calculate the actual rate - HDMI requires -0.6%..+0.5% */
|
||||
real_hz = DIV_ROUND_CLOSEST(real_clk_hz, div);
|
||||
|
||||
DRM_DEBUG_KMS("[CRTC:%u:%s] clk=%u %luHz div=%u real=%luHz\n",
|
||||
dcrtc->crtc.base.id, dcrtc->crtc.name,
|
||||
i, real_clk_hz, div, real_hz);
|
||||
|
||||
/* Avoid repeated division */
|
||||
if (real_hz < desired_hz) {
|
||||
permillage = real_hz / desired_khz;
|
||||
if (permillage < params->permillage_min)
|
||||
continue;
|
||||
} else {
|
||||
permillage = DIV_ROUND_UP(real_hz, desired_khz);
|
||||
if (permillage > params->permillage_max)
|
||||
continue;
|
||||
}
|
||||
goto found;
|
||||
}
|
||||
|
||||
return -ERANGE;
|
||||
|
||||
found:
|
||||
DRM_DEBUG_KMS("[CRTC:%u:%s] selected clk=%u %luHz div=%u real=%luHz\n",
|
||||
dcrtc->crtc.base.id, dcrtc->crtc.name,
|
||||
i, real_clk_hz, div, real_hz);
|
||||
|
||||
res->desired_clk_hz = desired_clk_hz;
|
||||
res->clk = clk;
|
||||
res->div = div;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
|
||||
struct resource *res, int irq, const struct armada_variant *variant,
|
||||
struct device_node *port)
|
||||
@ -737,7 +922,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
|
||||
dcrtc->variant = variant;
|
||||
dcrtc->base = base;
|
||||
dcrtc->num = drm->mode_config.num_crtc;
|
||||
dcrtc->clk = ERR_PTR(-EINVAL);
|
||||
dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0;
|
||||
dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;
|
||||
spin_lock_init(&dcrtc->irq_lock);
|
||||
@ -794,6 +978,12 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
|
||||
|
||||
drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
|
||||
|
||||
ret = drm_mode_crtc_set_gamma_size(&dcrtc->crtc, 256);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_crtc_enable_color_mgmt(&dcrtc->crtc, 0, false, 256);
|
||||
|
||||
return armada_overlay_plane_create(drm, 1 << dcrtc->num);
|
||||
|
||||
err_crtc_init:
|
||||
|
@ -39,10 +39,10 @@ struct armada_variant;
|
||||
struct armada_crtc {
|
||||
struct drm_crtc crtc;
|
||||
const struct armada_variant *variant;
|
||||
void *variant_data;
|
||||
unsigned num;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
struct clk *extclk[2];
|
||||
struct {
|
||||
uint32_t spu_v_h_total;
|
||||
uint32_t spu_v_porch;
|
||||
@ -75,6 +75,25 @@ struct armada_crtc {
|
||||
|
||||
void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
|
||||
|
||||
struct armada_clocking_params {
|
||||
unsigned long permillage_min;
|
||||
unsigned long permillage_max;
|
||||
u32 settable;
|
||||
u32 div_max;
|
||||
};
|
||||
|
||||
struct armada_clk_result {
|
||||
unsigned long desired_clk_hz;
|
||||
struct clk *clk;
|
||||
u32 div;
|
||||
};
|
||||
|
||||
int armada_crtc_select_clock(struct armada_crtc *dcrtc,
|
||||
struct armada_clk_result *res,
|
||||
const struct armada_clocking_params *params,
|
||||
struct clk *clks[], size_t num_clks,
|
||||
unsigned long desired_khz);
|
||||
|
||||
extern struct platform_driver armada_lcd_platform_driver;
|
||||
|
||||
#endif
|
||||
|
@ -28,50 +28,33 @@ static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada_debugfs_reg_show(struct seq_file *m, void *data)
|
||||
static int armada_debugfs_crtc_reg_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_device *dev = m->private;
|
||||
struct armada_private *priv = dev->dev_private;
|
||||
int n, i;
|
||||
struct armada_crtc *dcrtc = m->private;
|
||||
int i;
|
||||
|
||||
if (priv) {
|
||||
for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) {
|
||||
struct armada_crtc *dcrtc = priv->dcrtc[n];
|
||||
if (!dcrtc)
|
||||
continue;
|
||||
|
||||
for (i = 0x84; i <= 0x1c4; i += 4) {
|
||||
uint32_t v = readl_relaxed(dcrtc->base + i);
|
||||
seq_printf(m, "%u: 0x%04x: 0x%08x\n", n, i, v);
|
||||
}
|
||||
}
|
||||
for (i = 0x84; i <= 0x1c4; i += 4) {
|
||||
u32 v = readl_relaxed(dcrtc->base + i);
|
||||
seq_printf(m, "0x%04x: 0x%08x\n", i, v);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada_debugfs_reg_r_open(struct inode *inode, struct file *file)
|
||||
static int armada_debugfs_crtc_reg_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, armada_debugfs_reg_show, inode->i_private);
|
||||
return single_open(file, armada_debugfs_crtc_reg_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_reg_r = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = armada_debugfs_reg_r_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int armada_debugfs_write(struct file *file, const char __user *ptr,
|
||||
size_t len, loff_t *off)
|
||||
static int armada_debugfs_crtc_reg_write(struct file *file,
|
||||
const char __user *ptr, size_t len, loff_t *off)
|
||||
{
|
||||
struct drm_device *dev = file->private_data;
|
||||
struct armada_private *priv = dev->dev_private;
|
||||
struct armada_crtc *dcrtc = priv->dcrtc[0];
|
||||
char buf[32], *p;
|
||||
uint32_t reg, val;
|
||||
struct armada_crtc *dcrtc;
|
||||
unsigned long reg, mask, val;
|
||||
char buf[32];
|
||||
int ret;
|
||||
u32 v;
|
||||
|
||||
if (*off != 0)
|
||||
return 0;
|
||||
@ -84,24 +67,35 @@ static int armada_debugfs_write(struct file *file, const char __user *ptr,
|
||||
return ret;
|
||||
buf[len] = '\0';
|
||||
|
||||
reg = simple_strtoul(buf, &p, 16);
|
||||
if (!isspace(*p))
|
||||
if (sscanf(buf, "%lx %lx %lx", ®, &mask, &val) != 3)
|
||||
return -EINVAL;
|
||||
val = simple_strtoul(p + 1, NULL, 16);
|
||||
if (reg < 0x84 || reg > 0x1c4 || reg & 3)
|
||||
return -ERANGE;
|
||||
|
||||
if (reg >= 0x84 && reg <= 0x1c4)
|
||||
writel(val, dcrtc->base + reg);
|
||||
dcrtc = ((struct seq_file *)file->private_data)->private;
|
||||
v = readl(dcrtc->base + reg);
|
||||
v &= ~mask;
|
||||
v |= val & mask;
|
||||
writel(v, dcrtc->base + reg);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_reg_w = {
|
||||
static const struct file_operations armada_debugfs_crtc_reg_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.write = armada_debugfs_write,
|
||||
.llseek = noop_llseek,
|
||||
.open = armada_debugfs_crtc_reg_open,
|
||||
.read = seq_read,
|
||||
.write = armada_debugfs_crtc_reg_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc)
|
||||
{
|
||||
debugfs_create_file("armada-regs", 0600, dcrtc->crtc.debugfs_entry,
|
||||
dcrtc, &armada_debugfs_crtc_reg_fops);
|
||||
}
|
||||
|
||||
static struct drm_info_list armada_debugfs_list[] = {
|
||||
{ "gem_linear", armada_debugfs_gem_linear_show, 0 },
|
||||
};
|
||||
@ -109,24 +103,8 @@ static struct drm_info_list armada_debugfs_list[] = {
|
||||
|
||||
int armada_drm_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
struct dentry *de;
|
||||
int ret;
|
||||
|
||||
ret = drm_debugfs_create_files(armada_debugfs_list,
|
||||
ARMADA_DEBUGFS_ENTRIES,
|
||||
minor->debugfs_root, minor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
de = debugfs_create_file("reg", S_IFREG | S_IRUSR,
|
||||
minor->debugfs_root, minor->dev, &fops_reg_r);
|
||||
if (!de)
|
||||
return -ENOMEM;
|
||||
|
||||
de = debugfs_create_file("reg_wr", S_IFREG | S_IWUSR,
|
||||
minor->debugfs_root, minor->dev, &fops_reg_w);
|
||||
if (!de)
|
||||
return -ENOMEM;
|
||||
drm_debugfs_create_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES,
|
||||
minor->debugfs_root, minor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ void armada_fbdev_fini(struct drm_device *);
|
||||
|
||||
int armada_overlay_plane_create(struct drm_device *, unsigned long);
|
||||
|
||||
void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc);
|
||||
int armada_drm_debugfs_init(struct drm_minor *);
|
||||
|
||||
#endif
|
||||
|
@ -100,6 +100,17 @@ static int armada_drm_bind(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Remove early framebuffers */
|
||||
ret = drm_fb_helper_remove_conflicting_framebuffers(NULL,
|
||||
"armada-drm-fb",
|
||||
false);
|
||||
if (ret) {
|
||||
dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n",
|
||||
__func__, ret);
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->drm.dev_private = priv;
|
||||
|
||||
dev_set_drvdata(dev, &priv->drm);
|
||||
@ -171,6 +182,8 @@ static void armada_drm_unbind(struct device *dev)
|
||||
|
||||
drm_dev_unregister(&priv->drm);
|
||||
|
||||
drm_atomic_helper_shutdown(&priv->drm);
|
||||
|
||||
component_unbind_all(dev, &priv->drm);
|
||||
|
||||
drm_mode_config_cleanup(&priv->drm);
|
||||
@ -191,23 +204,15 @@ static int compare_dev_name(struct device *dev, void *data)
|
||||
}
|
||||
|
||||
static void armada_add_endpoints(struct device *dev,
|
||||
struct component_match **match, struct device_node *port)
|
||||
struct component_match **match, struct device_node *dev_node)
|
||||
{
|
||||
struct device_node *ep, *remote;
|
||||
|
||||
for_each_child_of_node(port, ep) {
|
||||
for_each_endpoint_of_node(dev_node, ep) {
|
||||
remote = of_graph_get_remote_port_parent(ep);
|
||||
if (!remote || !of_device_is_available(remote)) {
|
||||
of_node_put(remote);
|
||||
continue;
|
||||
} else if (!of_device_is_available(remote->parent)) {
|
||||
dev_warn(dev, "parent device of %pOF is not available\n",
|
||||
remote);
|
||||
of_node_put(remote);
|
||||
continue;
|
||||
}
|
||||
|
||||
drm_of_component_match_add(dev, match, compare_of, remote);
|
||||
if (remote && of_device_is_available(remote))
|
||||
drm_of_component_match_add(dev, match, compare_of,
|
||||
remote);
|
||||
of_node_put(remote);
|
||||
}
|
||||
}
|
||||
@ -229,7 +234,6 @@ static int armada_drm_probe(struct platform_device *pdev)
|
||||
|
||||
if (dev->platform_data) {
|
||||
char **devices = dev->platform_data;
|
||||
struct device_node *port;
|
||||
struct device *d;
|
||||
int i;
|
||||
|
||||
@ -245,10 +249,8 @@ static int armada_drm_probe(struct platform_device *pdev)
|
||||
for (i = 0; devices[i]; i++) {
|
||||
d = bus_find_device_by_name(&platform_bus_type, NULL,
|
||||
devices[i]);
|
||||
if (d && d->of_node) {
|
||||
for_each_child_of_node(d->of_node, port)
|
||||
armada_add_endpoints(dev, &match, port);
|
||||
}
|
||||
if (d && d->of_node)
|
||||
armada_add_endpoints(dev, &match, d->of_node);
|
||||
put_device(d);
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,16 @@ enum {
|
||||
ADV_VSYNC_H_OFF = 0xfff << 0,
|
||||
};
|
||||
|
||||
/* LCD_CFG_RDREG4F - Armada 510 only */
|
||||
enum {
|
||||
CFG_SRAM_WAIT = BIT(11),
|
||||
CFG_SMPN_FASTTX = BIT(10),
|
||||
CFG_DMA_ARB = BIT(9),
|
||||
CFG_DMA_WM_EN = BIT(8),
|
||||
CFG_DMA_WM_MASK = 0xff,
|
||||
#define CFG_DMA_WM(x) ((x) & CFG_DMA_WM_MASK)
|
||||
};
|
||||
|
||||
enum {
|
||||
CFG_565 = 0,
|
||||
CFG_1555 = 1,
|
||||
@ -169,6 +179,10 @@ enum {
|
||||
SRAM_READ = 0 << 14,
|
||||
SRAM_WRITE = 2 << 14,
|
||||
SRAM_INIT = 3 << 14,
|
||||
SRAM_GAMMA_YR = 0x0 << 8,
|
||||
SRAM_GAMMA_UG = 0x1 << 8,
|
||||
SRAM_GAMMA_VB = 0x2 << 8,
|
||||
SRAM_PALETTE = 0x3 << 8,
|
||||
SRAM_HWC32_RAM1 = 0xc << 8,
|
||||
SRAM_HWC32_RAM2 = 0xd << 8,
|
||||
SRAM_HWC32_RAMR = SRAM_HWC32_RAM1,
|
||||
@ -316,19 +330,4 @@ enum {
|
||||
PWRDN_IRQ_LEVEL = 1 << 0,
|
||||
};
|
||||
|
||||
static inline u32 armada_rect_hw_fp(struct drm_rect *r)
|
||||
{
|
||||
return (drm_rect_height(r) & 0xffff0000) | drm_rect_width(r) >> 16;
|
||||
}
|
||||
|
||||
static inline u32 armada_rect_hw(struct drm_rect *r)
|
||||
{
|
||||
return drm_rect_height(r) << 16 | (drm_rect_width(r) & 0x0000ffff);
|
||||
}
|
||||
|
||||
static inline u32 armada_rect_yx(struct drm_rect *r)
|
||||
{
|
||||
return (r)->y1 << 16 | ((r)->x1 & 0x0000ffff);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -27,7 +27,7 @@
|
||||
#define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601
|
||||
|
||||
struct armada_overlay_state {
|
||||
struct drm_plane_state base;
|
||||
struct armada_plane_state base;
|
||||
u32 colorkey_yr;
|
||||
u32 colorkey_ug;
|
||||
u32 colorkey_vb;
|
||||
@ -38,7 +38,7 @@ struct armada_overlay_state {
|
||||
u16 saturation;
|
||||
};
|
||||
#define drm_to_overlay_state(s) \
|
||||
container_of(s, struct armada_overlay_state, base)
|
||||
container_of(s, struct armada_overlay_state, base.base)
|
||||
|
||||
static inline u32 armada_spu_contrast(struct drm_plane_state *state)
|
||||
{
|
||||
@ -94,41 +94,39 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
|
||||
armada_reg_queue_mod(regs, idx,
|
||||
0, CFG_PDWN16x66 | CFG_PDWN32x66,
|
||||
LCD_SPU_SRAM_PARA1);
|
||||
val = armada_rect_hw_fp(&state->src);
|
||||
if (armada_rect_hw_fp(&old_state->src) != val)
|
||||
val = armada_src_hw(state);
|
||||
if (armada_src_hw(old_state) != val)
|
||||
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN);
|
||||
val = armada_rect_yx(&state->dst);
|
||||
if (armada_rect_yx(&old_state->dst) != val)
|
||||
val = armada_dst_yx(state);
|
||||
if (armada_dst_yx(old_state) != val)
|
||||
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN);
|
||||
val = armada_rect_hw(&state->dst);
|
||||
if (armada_rect_hw(&old_state->dst) != val)
|
||||
val = armada_dst_hw(state);
|
||||
if (armada_dst_hw(old_state) != val)
|
||||
armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);
|
||||
/* FIXME: overlay on an interlaced display */
|
||||
if (old_state->src.x1 != state->src.x1 ||
|
||||
old_state->src.y1 != state->src.y1 ||
|
||||
old_state->fb != state->fb) {
|
||||
old_state->fb != state->fb ||
|
||||
state->crtc->state->mode_changed) {
|
||||
const struct drm_format_info *format;
|
||||
u16 src_x, pitches[3];
|
||||
u32 addrs[2][3];
|
||||
u16 src_x;
|
||||
|
||||
armada_drm_plane_calc(state, addrs, pitches, false);
|
||||
|
||||
armada_reg_queue_set(regs, idx, addrs[0][0],
|
||||
armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
|
||||
LCD_SPU_DMA_START_ADDR_Y0);
|
||||
armada_reg_queue_set(regs, idx, addrs[0][1],
|
||||
armada_reg_queue_set(regs, idx, armada_addr(state, 0, 1),
|
||||
LCD_SPU_DMA_START_ADDR_U0);
|
||||
armada_reg_queue_set(regs, idx, addrs[0][2],
|
||||
armada_reg_queue_set(regs, idx, armada_addr(state, 0, 2),
|
||||
LCD_SPU_DMA_START_ADDR_V0);
|
||||
armada_reg_queue_set(regs, idx, addrs[1][0],
|
||||
armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),
|
||||
LCD_SPU_DMA_START_ADDR_Y1);
|
||||
armada_reg_queue_set(regs, idx, addrs[1][1],
|
||||
armada_reg_queue_set(regs, idx, armada_addr(state, 1, 1),
|
||||
LCD_SPU_DMA_START_ADDR_U1);
|
||||
armada_reg_queue_set(regs, idx, addrs[1][2],
|
||||
armada_reg_queue_set(regs, idx, armada_addr(state, 1, 2),
|
||||
LCD_SPU_DMA_START_ADDR_V1);
|
||||
|
||||
val = pitches[0] << 16 | pitches[0];
|
||||
val = armada_pitch(state, 0) << 16 | armada_pitch(state, 0);
|
||||
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC);
|
||||
val = pitches[1] << 16 | pitches[2];
|
||||
val = armada_pitch(state, 1) << 16 | armada_pitch(state, 2);
|
||||
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);
|
||||
|
||||
cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
|
||||
@ -146,6 +144,8 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
|
||||
src_x = state->src.x1 >> 16;
|
||||
if (format->num_planes == 1 && src_x & (format->hsub - 1))
|
||||
cfg ^= CFG_DMA_MOD(CFG_SWAPUV);
|
||||
if (to_armada_plane_state(state)->interlace)
|
||||
cfg |= CFG_DMA_FTOGGLE;
|
||||
cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |
|
||||
CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |
|
||||
CFG_SWAPYU | CFG_YUV2RGB) |
|
||||
@ -307,13 +307,10 @@ static void armada_overlay_reset(struct drm_plane *plane)
|
||||
if (plane->state)
|
||||
__drm_atomic_helper_plane_destroy_state(plane->state);
|
||||
kfree(plane->state);
|
||||
plane->state = NULL;
|
||||
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (state) {
|
||||
state->base.plane = plane;
|
||||
state->base.color_encoding = DEFAULT_ENCODING;
|
||||
state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
|
||||
state->base.rotation = DRM_MODE_ROTATE_0;
|
||||
state->colorkey_yr = 0xfefefe00;
|
||||
state->colorkey_ug = 0x01010100;
|
||||
state->colorkey_vb = 0x01010100;
|
||||
@ -323,8 +320,10 @@ static void armada_overlay_reset(struct drm_plane *plane)
|
||||
state->brightness = DEFAULT_BRIGHTNESS;
|
||||
state->contrast = DEFAULT_CONTRAST;
|
||||
state->saturation = DEFAULT_SATURATION;
|
||||
__drm_atomic_helper_plane_reset(plane, &state->base.base);
|
||||
state->base.base.color_encoding = DEFAULT_ENCODING;
|
||||
state->base.base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
|
||||
}
|
||||
plane->state = &state->base;
|
||||
}
|
||||
|
||||
struct drm_plane_state *
|
||||
@ -337,8 +336,9 @@ armada_overlay_duplicate_state(struct drm_plane *plane)
|
||||
|
||||
state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
|
||||
if (state)
|
||||
__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
|
||||
return &state->base;
|
||||
__drm_atomic_helper_plane_duplicate_state(plane,
|
||||
&state->base.base);
|
||||
return &state->base.base;
|
||||
}
|
||||
|
||||
static int armada_overlay_set_property(struct drm_plane *plane,
|
||||
|
@ -79,23 +79,6 @@ void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state,
|
||||
struct armada_regs *regs, bool interlaced)
|
||||
{
|
||||
u16 pitches[3];
|
||||
u32 addrs[2][3];
|
||||
unsigned i = 0;
|
||||
|
||||
armada_drm_plane_calc(state, addrs, pitches, interlaced);
|
||||
|
||||
/* write offset, base, and pitch */
|
||||
armada_reg_queue_set(regs, i, addrs[0][0], LCD_CFG_GRA_START_ADDR0);
|
||||
armada_reg_queue_set(regs, i, addrs[1][0], LCD_CFG_GRA_START_ADDR1);
|
||||
armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int armada_drm_plane_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *state)
|
||||
{
|
||||
@ -126,20 +109,50 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
|
||||
int armada_drm_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *state)
|
||||
{
|
||||
if (state->fb && !WARN_ON(!state->crtc)) {
|
||||
struct drm_crtc *crtc = state->crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
struct armada_plane_state *st = to_armada_plane_state(state);
|
||||
struct drm_crtc *crtc = state->crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
bool interlace;
|
||||
int ret;
|
||||
|
||||
if (state->state)
|
||||
crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
|
||||
else
|
||||
crtc_state = crtc->state;
|
||||
return drm_atomic_helper_check_plane_state(state, crtc_state,
|
||||
0, INT_MAX,
|
||||
true, false);
|
||||
} else {
|
||||
if (!state->fb || WARN_ON(!state->crtc)) {
|
||||
state->visible = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->state)
|
||||
crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
|
||||
else
|
||||
crtc_state = crtc->state;
|
||||
|
||||
ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0,
|
||||
INT_MAX, true, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
|
||||
if (interlace) {
|
||||
if ((state->dst.y1 | state->dst.y2) & 1)
|
||||
return -EINVAL;
|
||||
st->src_hw = drm_rect_height(&state->src) >> 17;
|
||||
st->dst_yx = state->dst.y1 >> 1;
|
||||
st->dst_hw = drm_rect_height(&state->dst) >> 1;
|
||||
} else {
|
||||
st->src_hw = drm_rect_height(&state->src) >> 16;
|
||||
st->dst_yx = state->dst.y1;
|
||||
st->dst_hw = drm_rect_height(&state->dst);
|
||||
}
|
||||
|
||||
st->src_hw <<= 16;
|
||||
st->src_hw |= drm_rect_width(&state->src) >> 16;
|
||||
st->dst_yx <<= 16;
|
||||
st->dst_yx |= state->dst.x1 & 0x0000ffff;
|
||||
st->dst_hw <<= 16;
|
||||
st->dst_hw |= drm_rect_width(&state->dst) & 0x0000ffff;
|
||||
|
||||
armada_drm_plane_calc(state, st->addrs, st->pitches, interlace);
|
||||
st->interlace = interlace;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -173,21 +186,25 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
val |= CFG_PDWN256x24;
|
||||
armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
|
||||
}
|
||||
val = armada_rect_hw_fp(&state->src);
|
||||
if (armada_rect_hw_fp(&old_state->src) != val)
|
||||
val = armada_src_hw(state);
|
||||
if (armada_src_hw(old_state) != val)
|
||||
armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
|
||||
val = armada_rect_yx(&state->dst);
|
||||
if (armada_rect_yx(&old_state->dst) != val)
|
||||
val = armada_dst_yx(state);
|
||||
if (armada_dst_yx(old_state) != val)
|
||||
armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
|
||||
val = armada_rect_hw(&state->dst);
|
||||
if (armada_rect_hw(&old_state->dst) != val)
|
||||
val = armada_dst_hw(state);
|
||||
if (armada_dst_hw(old_state) != val)
|
||||
armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
|
||||
if (old_state->src.x1 != state->src.x1 ||
|
||||
old_state->src.y1 != state->src.y1 ||
|
||||
old_state->fb != state->fb ||
|
||||
state->crtc->state->mode_changed) {
|
||||
idx += armada_drm_crtc_calc_fb(state, regs + idx,
|
||||
dcrtc->interlaced);
|
||||
armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
|
||||
LCD_CFG_GRA_START_ADDR0);
|
||||
armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),
|
||||
LCD_CFG_GRA_START_ADDR1);
|
||||
armada_reg_queue_mod(regs, idx, armada_pitch(state, 0), 0xffff,
|
||||
LCD_CFG_GRA_PITCH);
|
||||
}
|
||||
if (old_state->fb != state->fb ||
|
||||
state->crtc->state->mode_changed) {
|
||||
@ -197,7 +214,7 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
cfg |= CFG_PALETTE_ENA;
|
||||
if (state->visible)
|
||||
cfg |= CFG_GRA_ENA;
|
||||
if (dcrtc->interlaced)
|
||||
if (to_armada_plane_state(state)->interlace)
|
||||
cfg |= CFG_GRA_FTOGGLE;
|
||||
cfg_mask = CFG_GRAFORMAT |
|
||||
CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
|
||||
@ -248,7 +265,7 @@ static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
|
||||
/* Disable plane and power down most RAMs and FIFOs */
|
||||
armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
|
||||
armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
|
||||
CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66,
|
||||
CFG_PDWN32x32 | CFG_PDWN64x66,
|
||||
0, LCD_SPU_SRAM_PARA1);
|
||||
|
||||
dcrtc->regs_idx += idx;
|
||||
@ -262,12 +279,37 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
|
||||
.atomic_disable = armada_drm_primary_plane_atomic_disable,
|
||||
};
|
||||
|
||||
void armada_plane_reset(struct drm_plane *plane)
|
||||
{
|
||||
struct armada_plane_state *st;
|
||||
if (plane->state)
|
||||
__drm_atomic_helper_plane_destroy_state(plane->state);
|
||||
kfree(plane->state);
|
||||
st = kzalloc(sizeof(*st), GFP_KERNEL);
|
||||
if (st)
|
||||
__drm_atomic_helper_plane_reset(plane, &st->base);
|
||||
}
|
||||
|
||||
struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
|
||||
{
|
||||
struct armada_plane_state *st;
|
||||
|
||||
if (WARN_ON(!plane->state))
|
||||
return NULL;
|
||||
|
||||
st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
|
||||
if (st)
|
||||
__drm_atomic_helper_plane_duplicate_state(plane, &st->base);
|
||||
|
||||
return &st->base;
|
||||
}
|
||||
|
||||
static const struct drm_plane_funcs armada_primary_plane_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.destroy = drm_primary_helper_destroy,
|
||||
.reset = drm_atomic_helper_plane_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
.reset = armada_plane_reset,
|
||||
.atomic_duplicate_state = armada_plane_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,24 @@
|
||||
#ifndef ARMADA_PLANE_H
|
||||
#define ARMADA_PLANE_H
|
||||
|
||||
struct armada_plane_state {
|
||||
struct drm_plane_state base;
|
||||
u32 src_hw;
|
||||
u32 dst_yx;
|
||||
u32 dst_hw;
|
||||
u32 addrs[2][3];
|
||||
u16 pitches[3];
|
||||
bool interlace;
|
||||
};
|
||||
|
||||
#define to_armada_plane_state(st) \
|
||||
container_of(st, struct armada_plane_state, base)
|
||||
#define armada_src_hw(state) to_armada_plane_state(state)->src_hw
|
||||
#define armada_dst_yx(state) to_armada_plane_state(state)->dst_yx
|
||||
#define armada_dst_hw(state) to_armada_plane_state(state)->dst_hw
|
||||
#define armada_addr(state, f, p) to_armada_plane_state(state)->addrs[f][p]
|
||||
#define armada_pitch(state, n) to_armada_plane_state(state)->pitches[n]
|
||||
|
||||
void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
|
||||
u16 pitches[3], bool interlaced);
|
||||
int armada_drm_plane_prepare_fb(struct drm_plane *plane,
|
||||
@ -9,6 +27,11 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state);
|
||||
int armada_drm_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *state);
|
||||
void armada_plane_reset(struct drm_plane *plane);
|
||||
struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane);
|
||||
void armada_plane_destroy_state(struct drm_plane *plane,
|
||||
struct drm_plane_state *state);
|
||||
|
||||
int armada_drm_primary_plane_init(struct drm_device *drm,
|
||||
struct drm_plane *primary);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user