Commit f07b56e7 authored by Dave Airlie's avatar Dave Airlie

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: default avatarDave 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
parents a22719cc 837567c1
...@@ -14,18 +14,62 @@ ...@@ -14,18 +14,62 @@
#include "armada_drm.h" #include "armada_drm.h"
#include "armada_hw.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) static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
{ {
struct armada510_variant_data *v;
struct clk *clk; struct clk *clk;
int idx;
v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL);
if (!v)
return -ENOMEM;
dcrtc->variant_data = v;
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"); clk = devm_clk_get(dev, "ext_ref_clk1");
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk); return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
PTR_ERR(clk);
dcrtc->extclk[0] = clk; v->clks[1] = clk;
}
/* Lower the watermark so to eliminate jitter at higher bandwidths */ /*
armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); * 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 */ /* Initialise SPU register */
writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
...@@ -34,65 +78,77 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev) ...@@ -34,65 +78,77 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
return 0; 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. * Armada510 specific SCLK register selection.
* This gets called with sclk = NULL to test whether the mode is * This gets called with sclk = NULL to test whether the mode is
* supportable, and again with sclk != NULL to set the clocks up for * supportable, and again with sclk != NULL to set the clocks up for
* that. The former can return an error, but the latter is expected * that. The former can return an error, but the latter is expected
* not to. * 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, static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
const struct drm_display_mode *mode, uint32_t *sclk) const struct drm_display_mode *mode, uint32_t *sclk)
{ {
struct clk *clk = dcrtc->extclk[0]; struct armada510_variant_data *v = dcrtc->variant_data;
int ret; unsigned long desired_khz = mode->crtc_clock;
struct armada_clk_result res;
if (dcrtc->num == 1) int ret, idx;
return -EINVAL;
idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking,
if (IS_ERR(clk)) v->clks, ARRAY_SIZE(v->clks),
return PTR_ERR(clk); desired_khz);
if (idx < 0)
if (dcrtc->clk != clk) { return idx;
ret = clk_prepare_enable(clk);
ret = clk_prepare_enable(res.clk);
if (ret) if (ret)
return ret; return ret;
dcrtc->clk = clk;
}
if (sclk) { if (sclk) {
uint32_t rate, ref, div; clk_set_rate(res.clk, res.desired_clk_hz);
rate = mode->clock * 1000; *sclk = res.div | armada510_clk_sels[idx];
ref = clk_round_rate(clk, rate);
div = DIV_ROUND_UP(ref, rate);
if (div < 1)
div = 1;
clk_set_rate(clk, ref); /* We are now using this clock */
*sclk = div | SCLK_510_EXTCLK1; v->sel_clk = res.clk;
swap(dcrtc->clk, res.clk);
} }
clk_disable_unprepare(res.clk);
return 0; return 0;
} }
static void armada510_crtc_disable(struct armada_crtc *dcrtc) static void armada510_crtc_disable(struct armada_crtc *dcrtc)
{ {
if (!IS_ERR(dcrtc->clk)) { if (dcrtc->clk) {
clk_disable_unprepare(dcrtc->clk); clk_disable_unprepare(dcrtc->clk);
dcrtc->clk = ERR_PTR(-EINVAL); dcrtc->clk = NULL;
} }
} }
static void armada510_crtc_enable(struct armada_crtc *dcrtc, static void armada510_crtc_enable(struct armada_crtc *dcrtc,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
if (IS_ERR(dcrtc->clk)) { struct armada510_variant_data *v = dcrtc->variant_data;
dcrtc->clk = dcrtc->extclk[0];
WARN_ON(clk_prepare_enable(dcrtc->clk)); if (!dcrtc->clk && v->sel_clk) {
if (!WARN_ON(clk_prepare_enable(v->sel_clk)))
dcrtc->clk = v->sel_clk;
} }
} }
......
This diff is collapsed.
...@@ -39,10 +39,10 @@ struct armada_variant; ...@@ -39,10 +39,10 @@ struct armada_variant;
struct armada_crtc { struct armada_crtc {
struct drm_crtc crtc; struct drm_crtc crtc;
const struct armada_variant *variant; const struct armada_variant *variant;
void *variant_data;
unsigned num; unsigned num;
void __iomem *base; void __iomem *base;
struct clk *clk; struct clk *clk;
struct clk *extclk[2];
struct { struct {
uint32_t spu_v_h_total; uint32_t spu_v_h_total;
uint32_t spu_v_porch; uint32_t spu_v_porch;
...@@ -75,6 +75,25 @@ struct armada_crtc { ...@@ -75,6 +75,25 @@ struct armada_crtc {
void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); 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; extern struct platform_driver armada_lcd_platform_driver;
#endif #endif
...@@ -28,50 +28,33 @@ static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data) ...@@ -28,50 +28,33 @@ static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data)
return 0; 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_crtc *dcrtc = m->private;
struct armada_private *priv = dev->dev_private; int i;
int n, 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) { for (i = 0x84; i <= 0x1c4; i += 4) {
uint32_t v = readl_relaxed(dcrtc->base + i); u32 v = readl_relaxed(dcrtc->base + i);
seq_printf(m, "%u: 0x%04x: 0x%08x\n", n, i, v); seq_printf(m, "0x%04x: 0x%08x\n", i, v);
}
}
} }
return 0; 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 = { static int armada_debugfs_crtc_reg_write(struct file *file,
.owner = THIS_MODULE, const char __user *ptr, size_t len, loff_t *off)
.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)
{ {
struct drm_device *dev = file->private_data; struct armada_crtc *dcrtc;
struct armada_private *priv = dev->dev_private; unsigned long reg, mask, val;
struct armada_crtc *dcrtc = priv->dcrtc[0]; char buf[32];
char buf[32], *p;
uint32_t reg, val;
int ret; int ret;
u32 v;
if (*off != 0) if (*off != 0)
return 0; return 0;
...@@ -84,24 +67,35 @@ static int armada_debugfs_write(struct file *file, const char __user *ptr, ...@@ -84,24 +67,35 @@ static int armada_debugfs_write(struct file *file, const char __user *ptr,
return ret; return ret;
buf[len] = '\0'; buf[len] = '\0';
reg = simple_strtoul(buf, &p, 16); if (sscanf(buf, "%lx %lx %lx", &reg, &mask, &val) != 3)
if (!isspace(*p))
return -EINVAL; return -EINVAL;
val = simple_strtoul(p + 1, NULL, 16); if (reg < 0x84 || reg > 0x1c4 || reg & 3)
return -ERANGE;
if (reg >= 0x84 && reg <= 0x1c4) dcrtc = ((struct seq_file *)file->private_data)->private;
writel(val, dcrtc->base + reg); v = readl(dcrtc->base + reg);
v &= ~mask;
v |= val & mask;
writel(v, dcrtc->base + reg);
return len; return len;
} }
static const struct file_operations fops_reg_w = { static const struct file_operations armada_debugfs_crtc_reg_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = simple_open, .open = armada_debugfs_crtc_reg_open,
.write = armada_debugfs_write, .read = seq_read,
.llseek = noop_llseek, .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[] = { static struct drm_info_list armada_debugfs_list[] = {
{ "gem_linear", armada_debugfs_gem_linear_show, 0 }, { "gem_linear", armada_debugfs_gem_linear_show, 0 },
}; };
...@@ -109,24 +103,8 @@ static struct drm_info_list armada_debugfs_list[] = { ...@@ -109,24 +103,8 @@ static struct drm_info_list armada_debugfs_list[] = {
int armada_drm_debugfs_init(struct drm_minor *minor) int armada_drm_debugfs_init(struct drm_minor *minor)
{ {
struct dentry *de; drm_debugfs_create_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES,
int ret;
ret = drm_debugfs_create_files(armada_debugfs_list,
ARMADA_DEBUGFS_ENTRIES,
minor->debugfs_root, minor); 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;
return 0; return 0;
} }
...@@ -78,6 +78,7 @@ void armada_fbdev_fini(struct drm_device *); ...@@ -78,6 +78,7 @@ void armada_fbdev_fini(struct drm_device *);
int armada_overlay_plane_create(struct drm_device *, unsigned long); 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 *); int armada_drm_debugfs_init(struct drm_minor *);
#endif #endif
...@@ -100,6 +100,17 @@ static int armada_drm_bind(struct device *dev) ...@@ -100,6 +100,17 @@ static int armada_drm_bind(struct device *dev)
return ret; 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; priv->drm.dev_private = priv;
dev_set_drvdata(dev, &priv->drm); dev_set_drvdata(dev, &priv->drm);
...@@ -171,6 +182,8 @@ static void armada_drm_unbind(struct device *dev) ...@@ -171,6 +182,8 @@ static void armada_drm_unbind(struct device *dev)
drm_dev_unregister(&priv->drm); drm_dev_unregister(&priv->drm);
drm_atomic_helper_shutdown(&priv->drm);
component_unbind_all(dev, &priv->drm); component_unbind_all(dev, &priv->drm);
drm_mode_config_cleanup(&priv->drm); drm_mode_config_cleanup(&priv->drm);
...@@ -191,24 +204,16 @@ static int compare_dev_name(struct device *dev, void *data) ...@@ -191,24 +204,16 @@ static int compare_dev_name(struct device *dev, void *data)
} }
static void armada_add_endpoints(struct device *dev, 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; 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); remote = of_graph_get_remote_port_parent(ep);
if (!remote || !of_device_is_available(remote)) { if (remote && of_device_is_available(remote))
of_node_put(remote); drm_of_component_match_add(dev, match, compare_of,
continue;
} else if (!of_device_is_available(remote->parent)) {
dev_warn(dev, "parent device of %pOF is not available\n",
remote); remote);
of_node_put(remote); of_node_put(remote);
continue;
}
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) ...@@ -229,7 +234,6 @@ static int armada_drm_probe(struct platform_device *pdev)
if (dev->platform_data) { if (dev->platform_data) {
char **devices = dev->platform_data; char **devices = dev->platform_data;
struct device_node *port;
struct device *d; struct device *d;
int i; int i;
...@@ -245,10 +249,8 @@ static int armada_drm_probe(struct platform_device *pdev) ...@@ -245,10 +249,8 @@ static int armada_drm_probe(struct platform_device *pdev)
for (i = 0; devices[i]; i++) { for (i = 0; devices[i]; i++) {
d = bus_find_device_by_name(&platform_bus_type, NULL, d = bus_find_device_by_name(&platform_bus_type, NULL,
devices[i]); devices[i]);
if (d && d->of_node) { if (d && d->of_node)
for_each_child_of_node(d->of_node, port) armada_add_endpoints(dev, &match, d->of_node);
armada_add_endpoints(dev, &match, port);
}
put_device(d); put_device(d);
} }
} }
......
...@@ -88,6 +88,16 @@ enum { ...@@ -88,6 +88,16 @@ enum {
ADV_VSYNC_H_OFF = 0xfff << 0, 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 { enum {
CFG_565 = 0, CFG_565 = 0,
CFG_1555 = 1, CFG_1555 = 1,
...@@ -169,6 +179,10 @@ enum { ...@@ -169,6 +179,10 @@ enum {
SRAM_READ = 0 << 14, SRAM_READ = 0 << 14,
SRAM_WRITE = 2 << 14, SRAM_WRITE = 2 << 14,
SRAM_INIT = 3 << 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_RAM1 = 0xc << 8,
SRAM_HWC32_RAM2 = 0xd << 8, SRAM_HWC32_RAM2 = 0xd << 8,
SRAM_HWC32_RAMR = SRAM_HWC32_RAM1, SRAM_HWC32_RAMR = SRAM_HWC32_RAM1,
...@@ -316,19 +330,4 @@ enum { ...@@ -316,19 +330,4 @@ enum {
PWRDN_IRQ_LEVEL = 1 << 0, 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 #endif
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601 #define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601
struct armada_overlay_state { struct armada_overlay_state {
struct drm_plane_state base; struct armada_plane_state base;
u32 colorkey_yr; u32 colorkey_yr;
u32 colorkey_ug; u32 colorkey_ug;
u32 colorkey_vb; u32 colorkey_vb;
...@@ -38,7 +38,7 @@ struct armada_overlay_state { ...@@ -38,7 +38,7 @@ struct armada_overlay_state {
u16 saturation; u16 saturation;
}; };
#define drm_to_overlay_state(s) \ #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) 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, ...@@ -94,41 +94,39 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
armada_reg_queue_mod(regs, idx, armada_reg_queue_mod(regs, idx,
0, CFG_PDWN16x66 | CFG_PDWN32x66, 0, CFG_PDWN16x66 | CFG_PDWN32x66,
LCD_SPU_SRAM_PARA1); LCD_SPU_SRAM_PARA1);
val = armada_rect_hw_fp(&state->src); val = armada_src_hw(state);
if (armada_rect_hw_fp(&old_state->src) != val) if (armada_src_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN); armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN);
val = armada_rect_yx(&state->dst); val = armada_dst_yx(state);
if (armada_rect_yx(&old_state->dst) != val) if (armada_dst_yx(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN); armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN);
val = armada_rect_hw(&state->dst); val = armada_dst_hw(state);
if (armada_rect_hw(&old_state->dst) != val) if (armada_dst_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN); armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);
/* FIXME: overlay on an interlaced display */ /* FIXME: overlay on an interlaced display */
if (old_state->src.x1 != state->src.x1 || if (old_state->src.x1 != state->src.x1 ||
old_state->src.y1 != state->src.y1 || 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; const struct drm_format_info *format;
u16 src_x, pitches[3]; u16 src_x;
u32 addrs[2][3];
armada_drm_plane_calc(state, addrs, pitches, false); armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
armada_reg_queue_set(regs, idx, addrs[0][0],
LCD_SPU_DMA_START_ADDR_Y0); 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); 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); 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); 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); 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); 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); 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); armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);
cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | 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, ...@@ -146,6 +144,8 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
src_x = state->src.x1 >> 16; src_x = state->src.x1 >> 16;
if (format->num_planes == 1 && src_x & (format->hsub - 1)) if (format->num_planes == 1 && src_x & (format->hsub - 1))
cfg ^= CFG_DMA_MOD(CFG_SWAPUV); 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_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |
CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |
CFG_SWAPYU | CFG_YUV2RGB) | CFG_SWAPYU | CFG_YUV2RGB) |
...@@ -307,13 +307,10 @@ static void armada_overlay_reset(struct drm_plane *plane) ...@@ -307,13 +307,10 @@ static void armada_overlay_reset(struct drm_plane *plane)
if (plane->state) if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state); __drm_atomic_helper_plane_destroy_state(plane->state);
kfree(plane->state); kfree(plane->state);
plane->state = NULL;
state = kzalloc(sizeof(*state), GFP_KERNEL); state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state) { 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_yr = 0xfefefe00;
state->colorkey_ug = 0x01010100; state->colorkey_ug = 0x01010100;
state->colorkey_vb = 0x01010100; state->colorkey_vb = 0x01010100;
...@@ -323,8 +320,10 @@ static void armada_overlay_reset(struct drm_plane *plane) ...@@ -323,8 +320,10 @@ static void armada_overlay_reset(struct drm_plane *plane)
state->brightness = DEFAULT_BRIGHTNESS; state->brightness = DEFAULT_BRIGHTNESS;
state->contrast = DEFAULT_CONTRAST; state->contrast = DEFAULT_CONTRAST;
state->saturation = DEFAULT_SATURATION; 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 * struct drm_plane_state *
...@@ -337,8 +336,9 @@ armada_overlay_duplicate_state(struct drm_plane *plane) ...@@ -337,8 +336,9 @@ armada_overlay_duplicate_state(struct drm_plane *plane)
state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL); state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
if (state) if (state)
__drm_atomic_helper_plane_duplicate_state(plane, &state->base); __drm_atomic_helper_plane_duplicate_state(plane,
return &state->base; &state->base.base);
return &state->base.base;
} }
static int armada_overlay_set_property(struct drm_plane *plane, 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], ...@@ -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, int armada_drm_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
...@@ -126,20 +109,50 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane, ...@@ -126,20 +109,50 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
int armada_drm_plane_atomic_check(struct drm_plane *plane, int armada_drm_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
if (state->fb && !WARN_ON(!state->crtc)) { struct armada_plane_state *st = to_armada_plane_state(state);
struct drm_crtc *crtc = state->crtc; struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
bool interlace;
int ret;
if (!state->fb || WARN_ON(!state->crtc)) {
state->visible = false;
return 0;
}
if (state->state) if (state->state)
crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
else else
crtc_state = crtc->state; crtc_state = crtc->state;
return drm_atomic_helper_check_plane_state(state, crtc_state,
0, INT_MAX, ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0,
true, false); 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 { } else {
state->visible = false; 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; return 0;
} }
...@@ -173,21 +186,25 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, ...@@ -173,21 +186,25 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
val |= CFG_PDWN256x24; val |= CFG_PDWN256x24;
armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1); armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
} }
val = armada_rect_hw_fp(&state->src); val = armada_src_hw(state);
if (armada_rect_hw_fp(&old_state->src) != val) if (armada_src_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN); armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
val = armada_rect_yx(&state->dst); val = armada_dst_yx(state);
if (armada_rect_yx(&old_state->dst) != val) if (armada_dst_yx(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN); armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
val = armada_rect_hw(&state->dst); val = armada_dst_hw(state);
if (armada_rect_hw(&old_state->dst) != val) if (armada_dst_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN); armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
if (old_state->src.x1 != state->src.x1 || if (old_state->src.x1 != state->src.x1 ||
old_state->src.y1 != state->src.y1 || old_state->src.y1 != state->src.y1 ||
old_state->fb != state->fb || old_state->fb != state->fb ||
state->crtc->state->mode_changed) { state->crtc->state->mode_changed) {
idx += armada_drm_crtc_calc_fb(state, regs + idx, armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
dcrtc->interlaced); 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 || if (old_state->fb != state->fb ||
state->crtc->state->mode_changed) { state->crtc->state->mode_changed) {
...@@ -197,7 +214,7 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, ...@@ -197,7 +214,7 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
cfg |= CFG_PALETTE_ENA; cfg |= CFG_PALETTE_ENA;
if (state->visible) if (state->visible)
cfg |= CFG_GRA_ENA; cfg |= CFG_GRA_ENA;
if (dcrtc->interlaced) if (to_armada_plane_state(state)->interlace)
cfg |= CFG_GRA_FTOGGLE; cfg |= CFG_GRA_FTOGGLE;
cfg_mask = CFG_GRAFORMAT | cfg_mask = CFG_GRAFORMAT |
CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
...@@ -248,7 +265,7 @@ static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane, ...@@ -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 */ /* 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, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 | 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); 0, LCD_SPU_SRAM_PARA1);
dcrtc->regs_idx += idx; dcrtc->regs_idx += idx;
...@@ -262,12 +279,37 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { ...@@ -262,12 +279,37 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
.atomic_disable = armada_drm_primary_plane_atomic_disable, .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 = { static const struct drm_plane_funcs armada_primary_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane, .update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane, .disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_primary_helper_destroy, .destroy = drm_primary_helper_destroy,
.reset = drm_atomic_helper_plane_reset, .reset = armada_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_duplicate_state = armada_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
}; };
......
#ifndef ARMADA_PLANE_H #ifndef ARMADA_PLANE_H
#define 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], void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
u16 pitches[3], bool interlaced); u16 pitches[3], bool interlaced);
int armada_drm_plane_prepare_fb(struct drm_plane *plane, int armada_drm_plane_prepare_fb(struct drm_plane *plane,
...@@ -9,6 +27,11 @@ void armada_drm_plane_cleanup_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); struct drm_plane_state *old_state);
int armada_drm_plane_atomic_check(struct drm_plane *plane, int armada_drm_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state); 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, int armada_drm_primary_plane_init(struct drm_device *drm,
struct drm_plane *primary); struct drm_plane *primary);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment