Allwinner sun4i DRM fixes for 4.9
A few fixes for the sun4i drm driver that range, including some fixes that might prevent multiple planes from working depending on the sequence where they are enabled. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJX44UwAAoJEBx+YmzsjxAgo+AQAKiv91r8qNidJ9I5dK4bLHVs 8wUkGgmdMSN/TIDtdxRwcNKkCG6D+ieyUCkeU2Tvop9QSK4vO5ZVh23d8/H9GEPh ebhHoPUQ76JwrLLxD4bJZ7+dcgOExLOFuM54275SYh+YVzEzSdwY7z4kD3O0H9fm 6RiuPVnehnkgyQGtUMpU/HfFhlwDEwpsJPbDb/RWnpN4C7o4kGP6+kDsJLh4vhyT 2wd9XXCXMKQrrxx7krppqFlAcBDUIfOpQcvceDopG8/xGJaGRyH64UGMwjnPrdGS 5kOqNg1/YwzSM2q/WSXziIh3o6RHuh9pyBnrcVPgpA731R744n9GrrclR/8Vkybp Bka1Rl4w7A/pw1HB2uOgH89KSFbb0rwEb5Zg0Oh4BfK6h2JUXkiscx4Q9JT5/H4T pUr51cxazGeHwV6KeMGt5ogpQcgtu93bcJnlbFtulnh/LQIXDVgFA/0oUK4vdnaz VRW8G8ZMl8sikMwxvyNzrf6iF5aXhM7eKa4xr4HqdND5skXe4CDZyvxZ/kvqO0eG 0Pf4VmlcMP8VV/I1lyHPw9ggQLsEO0dgLvvWmkOu1uOc6yYTfKrf8GnGjfUabxYj 3l3DIHnEBr6mFOFI/1PuD69urHt/IwnWsMCMdmbru+G74mKJ8cLLlEgF3FcyXEbV F8eSyPkSXVBTp4mV8kh3 =Ondz -----END PGP SIGNATURE----- Merge tag 'sunxi-drm-fixes-for-4.9' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into drm-next Allwinner sun4i DRM fixes for 4.9 A few fixes for the sun4i drm driver that range, including some fixes that might prevent multiple planes from working depending on the sequence where they are enabled. * tag 'sunxi-drm-fixes-for-4.9' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux: drm/sun4i: Fix the high buffer address mask drm/sun4i: tv: Check mode pointer drm/sun4i: Fix formats usable by the primary plane drm/sun4i: dotclock: Round to closest clock rate drm/sun4i: Fix sparse warnings drm/sun4i: dotclock: Allow divider = 127 drm/sun4i: dotclock: Fix clock rate read back calcation drm/sun4i: backend: remove redundant dev_err call in sun4i_backend_bind()
This commit is contained in:
Коммит
a4a7fbb401
|
@ -83,8 +83,13 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
|
|||
}
|
||||
EXPORT_SYMBOL(sun4i_backend_layer_enable);
|
||||
|
||||
static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)
|
||||
static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
|
||||
u32 format, u32 *mode)
|
||||
{
|
||||
if ((plane->type == DRM_PLANE_TYPE_PRIMARY) &&
|
||||
(format == DRM_FORMAT_ARGB8888))
|
||||
format = DRM_FORMAT_XRGB8888;
|
||||
|
||||
switch (format) {
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
*mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888;
|
||||
|
@ -164,7 +169,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
|
|||
DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
|
||||
interlaced ? "on" : "off");
|
||||
|
||||
ret = sun4i_backend_drm_format_to_layer(fb->pixel_format, &val);
|
||||
ret = sun4i_backend_drm_format_to_layer(plane, fb->pixel_format, &val);
|
||||
if (ret) {
|
||||
DRM_DEBUG_DRIVER("Invalid format\n");
|
||||
return val;
|
||||
|
@ -288,10 +293,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
|
|||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(regs)) {
|
||||
dev_err(dev, "Couldn't map the backend registers\n");
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
}
|
||||
|
||||
backend->regs = devm_regmap_init_mmio(dev, regs,
|
||||
&sun4i_backend_regmap_config);
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
#define SUN4I_BACKEND_LAYFB_L32ADD_REG(l) (0x850 + (0x4 * (l)))
|
||||
|
||||
#define SUN4I_BACKEND_LAYFB_H4ADD_REG 0x860
|
||||
#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l) GENMASK(3 + ((l) * 8), 0)
|
||||
#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l) GENMASK(3 + ((l) * 8), (l) * 8)
|
||||
#define SUN4I_BACKEND_LAYFB_H4ADD(l, val) ((val) << ((l) * 8))
|
||||
|
||||
#define SUN4I_BACKEND_REGBUFFCTL_REG 0x870
|
||||
|
|
|
@ -62,7 +62,7 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
|
|||
regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val);
|
||||
|
||||
val >>= SUN4I_TCON0_DCLK_DIV_SHIFT;
|
||||
val &= SUN4I_TCON0_DCLK_DIV_WIDTH;
|
||||
val &= (1 << SUN4I_TCON0_DCLK_DIV_WIDTH) - 1;
|
||||
|
||||
if (!val)
|
||||
val = 1;
|
||||
|
@ -77,7 +77,7 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
u8 best_div = 1;
|
||||
int i;
|
||||
|
||||
for (i = 6; i < 127; i++) {
|
||||
for (i = 6; i <= 127; i++) {
|
||||
unsigned long ideal = rate * i;
|
||||
unsigned long rounded;
|
||||
|
||||
|
@ -90,7 +90,8 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if ((rounded < ideal) && (rounded > best_parent)) {
|
||||
if (abs(rate - rounded / i) <
|
||||
abs(rate - best_parent / best_div)) {
|
||||
best_parent = rounded;
|
||||
best_div = i;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,12 @@
|
|||
#include "sun4i_drv.h"
|
||||
#include "sun4i_layer.h"
|
||||
|
||||
#define SUN4I_NUM_LAYERS 2
|
||||
struct sun4i_plane_desc {
|
||||
enum drm_plane_type type;
|
||||
u8 pipe;
|
||||
const uint32_t *formats;
|
||||
uint32_t nformats;
|
||||
};
|
||||
|
||||
static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *state)
|
||||
|
@ -65,14 +70,35 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
|
|||
.update_plane = drm_atomic_helper_update_plane,
|
||||
};
|
||||
|
||||
static const uint32_t sun4i_backend_layer_formats[] = {
|
||||
static const uint32_t sun4i_backend_layer_formats_primary[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
};
|
||||
|
||||
static const uint32_t sun4i_backend_layer_formats_overlay[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
};
|
||||
|
||||
static const struct sun4i_plane_desc sun4i_backend_planes[] = {
|
||||
{
|
||||
.type = DRM_PLANE_TYPE_PRIMARY,
|
||||
.pipe = 0,
|
||||
.formats = sun4i_backend_layer_formats_primary,
|
||||
.nformats = ARRAY_SIZE(sun4i_backend_layer_formats_primary),
|
||||
},
|
||||
{
|
||||
.type = DRM_PLANE_TYPE_OVERLAY,
|
||||
.pipe = 1,
|
||||
.formats = sun4i_backend_layer_formats_overlay,
|
||||
.nformats = ARRAY_SIZE(sun4i_backend_layer_formats_overlay),
|
||||
},
|
||||
};
|
||||
|
||||
static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
||||
enum drm_plane_type type)
|
||||
const struct sun4i_plane_desc *plane)
|
||||
{
|
||||
struct sun4i_drv *drv = drm->dev_private;
|
||||
struct sun4i_layer *layer;
|
||||
|
@ -84,10 +110,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
|||
|
||||
ret = drm_universal_plane_init(drm, &layer->plane, BIT(0),
|
||||
&sun4i_backend_layer_funcs,
|
||||
sun4i_backend_layer_formats,
|
||||
ARRAY_SIZE(sun4i_backend_layer_formats),
|
||||
type,
|
||||
NULL);
|
||||
plane->formats, plane->nformats,
|
||||
plane->type, NULL);
|
||||
if (ret) {
|
||||
dev_err(drm->dev, "Couldn't initialize layer\n");
|
||||
return ERR_PTR(ret);
|
||||
|
@ -97,7 +121,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
|||
&sun4i_backend_layer_helper_funcs);
|
||||
layer->drv = drv;
|
||||
|
||||
if (type == DRM_PLANE_TYPE_PRIMARY)
|
||||
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
|
||||
drv->primary = &layer->plane;
|
||||
|
||||
return layer;
|
||||
|
@ -109,8 +133,8 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
|
|||
struct sun4i_layer **layers;
|
||||
int i;
|
||||
|
||||
layers = devm_kcalloc(drm->dev, SUN4I_NUM_LAYERS, sizeof(**layers),
|
||||
GFP_KERNEL);
|
||||
layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes),
|
||||
sizeof(**layers), GFP_KERNEL);
|
||||
if (!layers)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
@ -135,13 +159,11 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
|
|||
* SoCs that support it, sprites could fill the need for more
|
||||
* layers.
|
||||
*/
|
||||
for (i = 0; i < SUN4I_NUM_LAYERS; i++) {
|
||||
enum drm_plane_type type = (i == 0)
|
||||
? DRM_PLANE_TYPE_PRIMARY
|
||||
: DRM_PLANE_TYPE_OVERLAY;
|
||||
for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
|
||||
const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
|
||||
struct sun4i_layer *layer = layers[i];
|
||||
|
||||
layer = sun4i_layer_init_one(drm, type);
|
||||
layer = sun4i_layer_init_one(drm, plane);
|
||||
if (IS_ERR(layer)) {
|
||||
dev_err(drm->dev, "Couldn't initialize %s plane\n",
|
||||
i ? "overlay" : "primary");
|
||||
|
@ -149,10 +171,10 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
|
|||
};
|
||||
|
||||
DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
|
||||
i ? "overlay" : "primary", i);
|
||||
i ? "overlay" : "primary", plane->pipe);
|
||||
regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(i));
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
|
||||
|
||||
layer->id = i;
|
||||
};
|
||||
|
|
|
@ -161,10 +161,10 @@ struct tv_mode {
|
|||
bool dac3_en;
|
||||
bool dac_bit25_en;
|
||||
|
||||
struct color_gains *color_gains;
|
||||
struct burst_levels *burst_levels;
|
||||
struct video_levels *video_levels;
|
||||
struct resync_parameters *resync_params;
|
||||
const struct color_gains *color_gains;
|
||||
const struct burst_levels *burst_levels;
|
||||
const struct video_levels *video_levels;
|
||||
const struct resync_parameters *resync_params;
|
||||
};
|
||||
|
||||
struct sun4i_tv {
|
||||
|
@ -178,39 +178,39 @@ struct sun4i_tv {
|
|||
struct sun4i_drv *drv;
|
||||
};
|
||||
|
||||
struct video_levels ntsc_video_levels = {
|
||||
static const struct video_levels ntsc_video_levels = {
|
||||
.black = 282, .blank = 240,
|
||||
};
|
||||
|
||||
struct video_levels pal_video_levels = {
|
||||
static const struct video_levels pal_video_levels = {
|
||||
.black = 252, .blank = 252,
|
||||
};
|
||||
|
||||
struct burst_levels ntsc_burst_levels = {
|
||||
static const struct burst_levels ntsc_burst_levels = {
|
||||
.cb = 79, .cr = 0,
|
||||
};
|
||||
|
||||
struct burst_levels pal_burst_levels = {
|
||||
static const struct burst_levels pal_burst_levels = {
|
||||
.cb = 40, .cr = 40,
|
||||
};
|
||||
|
||||
struct color_gains ntsc_color_gains = {
|
||||
static const struct color_gains ntsc_color_gains = {
|
||||
.cb = 160, .cr = 160,
|
||||
};
|
||||
|
||||
struct color_gains pal_color_gains = {
|
||||
static const struct color_gains pal_color_gains = {
|
||||
.cb = 224, .cr = 224,
|
||||
};
|
||||
|
||||
struct resync_parameters ntsc_resync_parameters = {
|
||||
static const struct resync_parameters ntsc_resync_parameters = {
|
||||
.field = false, .line = 14, .pixel = 12,
|
||||
};
|
||||
|
||||
struct resync_parameters pal_resync_parameters = {
|
||||
static const struct resync_parameters pal_resync_parameters = {
|
||||
.field = true, .line = 13, .pixel = 12,
|
||||
};
|
||||
|
||||
struct tv_mode tv_modes[] = {
|
||||
static const struct tv_mode tv_modes[] = {
|
||||
{
|
||||
.name = "NTSC",
|
||||
.mode = SUN4I_TVE_CFG0_RES_480i,
|
||||
|
@ -289,13 +289,13 @@ drm_connector_to_sun4i_tv(struct drm_connector *connector)
|
|||
* So far, it doesn't seem to be preserved when the mode is passed by
|
||||
* to mode_set for some reason.
|
||||
*/
|
||||
static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
|
||||
static const struct tv_mode *sun4i_tv_find_tv_by_mode(const struct drm_display_mode *mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* First try to identify the mode by name */
|
||||
for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
|
||||
struct tv_mode *tv_mode = &tv_modes[i];
|
||||
const struct tv_mode *tv_mode = &tv_modes[i];
|
||||
|
||||
DRM_DEBUG_DRIVER("Comparing mode %s vs %s",
|
||||
mode->name, tv_mode->name);
|
||||
|
@ -306,7 +306,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
|
|||
|
||||
/* Then by number of lines */
|
||||
for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
|
||||
struct tv_mode *tv_mode = &tv_modes[i];
|
||||
const struct tv_mode *tv_mode = &tv_modes[i];
|
||||
|
||||
DRM_DEBUG_DRIVER("Comparing mode %s vs %s (X: %d vs %d)",
|
||||
mode->name, tv_mode->name,
|
||||
|
@ -319,7 +319,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void sun4i_tv_mode_to_drm_mode(struct tv_mode *tv_mode,
|
||||
static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("Creating mode %s\n", mode->name);
|
||||
|
@ -386,7 +386,7 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
|
|||
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
|
||||
struct sun4i_drv *drv = tv->drv;
|
||||
struct sun4i_tcon *tcon = drv->tcon;
|
||||
struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
|
||||
const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
|
||||
|
||||
sun4i_tcon1_mode_set(tcon, mode);
|
||||
|
||||
|
@ -507,8 +507,14 @@ static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
|
||||
struct drm_display_mode *mode = drm_mode_create(connector->dev);
|
||||
struct tv_mode *tv_mode = &tv_modes[i];
|
||||
struct drm_display_mode *mode;
|
||||
const struct tv_mode *tv_mode = &tv_modes[i];
|
||||
|
||||
mode = drm_mode_create(connector->dev);
|
||||
if (!mode) {
|
||||
DRM_ERROR("Failed to create a new display mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
strcpy(mode->name, tv_mode->name);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче