drm-misc-next for 4.17:

UAPI Changes:
  plane: Add color encoding/range properties (Jyri)
  nouveau: Replace iturbt_709 property with color_encoding property (Ville)
 
 Core Changes:
  atomic: Move plane clipping into plane check helper (Ville)
  property: Multiple new property checks/verification (Ville)
 
 Driver Changes:
  rockchip: Fixes & improvements for rk3399/chromebook plus (various)
  sun4i: Add H3/H5 HDMI support (Jernej)
  i915: Add support for limited/full-range ycbcr toggling (Ville)
  pl111: Add bandwidth checking/limiting (Linus)
 
 Cc: Jernej Skrabec <jernej.skrabec@siol.net>
 Cc: Jyri Sarha <jsarha@ti.com>
 Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
 Cc: Linus Walleij <linus.walleij@linaro.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEfxcpfMSgdnQMs+QqlvcN/ahKBwoFAlqiy/cACgkQlvcN/ahK
 BwpkyQgAjqswNsnUP62lEow2MXoxDYAhyIh4PGR/fIp1/+pVm+UOOSMKJyQCVkPb
 6M4svzPXdawcPrIBFzfb17N73PqRw4S768N2NgiSbDEDdIW6VtzE+qX8z/tu0nFy
 WVlm3ilqy8YSHy9f4Wx8a4bDh8OWX4ElsUbxrADuun/+7zYFsbiIL2/NQk3nexVF
 ZgWyoyJ2XlSkUn07ghjoBkNTvJ2GCh/G9QFaFQu8LfAXhj60XAcWOH0/lI0hPdCP
 4JhAGZh1SDHoNxSFwriIw2k4GINLaHjGfDIQVvEtPwGOLJe9jH2KuuAdxahuT+yz
 tOn91ufpapxW9BUQoJHr/e6d0/CNqw==
 =gTcX
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2018-03-09-3' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 4.17:

UAPI Changes:
 plane: Add color encoding/range properties (Jyri)
 nouveau: Replace iturbt_709 property with color_encoding property (Ville)

Core Changes:
 atomic: Move plane clipping into plane check helper (Ville)
 property: Multiple new property checks/verification (Ville)

Driver Changes:
 rockchip: Fixes & improvements for rk3399/chromebook plus (various)
 sun4i: Add H3/H5 HDMI support (Jernej)
 i915: Add support for limited/full-range ycbcr toggling (Ville)
 pl111: Add bandwidth checking/limiting (Linus)

Cc: Jernej Skrabec <jernej.skrabec@siol.net>
Cc: Jyri Sarha <jsarha@ti.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Linus Walleij <linus.walleij@linaro.org>

* tag 'drm-misc-next-2018-03-09-3' of git://anongit.freedesktop.org/drm/drm-misc: (85 commits)
  drm/rockchip: Don't use atomic constructs for psr
  drm/rockchip: analogix_dp: set psr activate/deactivate when enable/disable bridge
  drm/rockchip: dw_hdmi: Move HDMI vpll clock enable to bind()
  drm/rockchip: inno_hdmi: reorder clk_disable_unprepare call in unbind
  drm/rockchip: inno_hdmi: Fix error handling path.
  drm/rockchip: dw-mipi-dsi: Fix connector and encoder cleanup.
  drm/nouveau: Replace the iturbt_709 prop with the standard COLOR_ENCODING prop
  drm/pl111: Use max memory bandwidth for resolution
  drm/bridge: sii902x: Retry status read after DDI I2C
  drm/pl111: Handle the RealView variant separately
  drm/pl111: Make the default BPP a per-variant variable
  drm: simple_kms_helper: Fix .mode_valid() documentation
  bridge: Elaborate a bit on dumb VGA bridges in Kconfig
  drm/atomic: Add new reverse iterator over all plane state (V2)
  drm: Reject bad property flag combinations
  drm: Make property flags u32
  drm/uapi: Deprecate DRM_MODE_PROP_PENDING
  drm: WARN when trying to add enum value > 63 to a bitmask property
  drm: WARN when trying add enum values to non-enum/bitmask properties
  drm: Reject replacing property enum values
  ...
This commit is contained in:
Dave Airlie 2018-03-14 10:59:16 +10:00
commit 0b8eeac5c6
96 changed files with 1802 additions and 680 deletions

View File

@ -102,6 +102,7 @@ DWC HDMI PHY
Required properties:
- compatible: value must be one of:
* allwinner,sun8i-a83t-hdmi-phy
* allwinner,sun8i-h3-hdmi-phy
- reg: base address and size of memory-mapped region
- clocks: phandles to the clocks feeding the HDMI PHY
* bus: the HDMI PHY interface clock
@ -110,6 +111,9 @@ Required properties:
- resets: phandle to the reset controller driving the PHY
- reset-names: must be "phy"
H3 HDMI PHY requires additional clock:
- pll-0: parent of phy clock
TV Encoder
----------
@ -275,6 +279,7 @@ Required properties:
- compatible: value must be one of:
* allwinner,sun8i-a83t-de2-mixer-0
* allwinner,sun8i-a83t-de2-mixer-1
* allwinner,sun8i-h3-de2-mixer-0
* allwinner,sun8i-v3s-de2-mixer
- reg: base address and size of the memory-mapped region.
- clocks: phandles to the clocks feeding the mixer
@ -305,6 +310,7 @@ Required properties:
* allwinner,sun7i-a20-display-engine
* allwinner,sun8i-a33-display-engine
* allwinner,sun8i-a83t-display-engine
* allwinner,sun8i-h3-display-engine
* allwinner,sun8i-v3s-display-engine
- allwinner,pipelines: list of phandle to the display engine

View File

@ -229,7 +229,6 @@ static const struct drm_crtc_helper_funcs hdlcd_crtc_helper_funcs = {
static int hdlcd_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct drm_rect clip = { 0 };
struct drm_crtc_state *crtc_state;
u32 src_h = state->src_h >> 16;
@ -249,11 +248,7 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane,
return -EINVAL;
}
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
return drm_atomic_helper_check_plane_state(state, crtc_state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, true);

View File

@ -141,18 +141,13 @@ static int malidp_se_check_scaling(struct malidp_plane *mp,
struct drm_crtc_state *crtc_state =
drm_atomic_get_existing_crtc_state(state->state, state->crtc);
struct malidp_crtc_state *mc;
struct drm_rect clip = { 0 };
u32 src_w, src_h;
int ret;
if (!crtc_state)
return -EINVAL;
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
0, INT_MAX, true, true);
if (ret)
return ret;

View File

@ -1200,13 +1200,14 @@ static int armada_drm_primary_update(struct drm_plane *plane,
.crtc_h = crtc_h,
.rotation = DRM_MODE_ROTATE_0,
};
const struct drm_rect clip = {
.x2 = crtc->mode.hdisplay,
.y2 = crtc->mode.vdisplay,
struct drm_crtc_state crtc_state = {
.crtc = crtc,
.enable = crtc->enabled,
.mode = crtc->mode,
};
int ret;
ret = drm_atomic_helper_check_plane_state(&state, crtc->state, &clip, 0,
ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, 0,
INT_MAX, true, false);
if (ret)
return ret;

View File

@ -205,9 +205,10 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
.crtc_h = crtc_h,
.rotation = DRM_MODE_ROTATE_0,
};
const struct drm_rect clip = {
.x2 = crtc->mode.hdisplay,
.y2 = crtc->mode.vdisplay,
struct drm_crtc_state crtc_state = {
.crtc = crtc,
.enable = crtc->enabled,
.mode = crtc->mode,
};
int ret;
@ -215,7 +216,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
crtc_x, crtc_y, crtc_w, crtc_h,
src_x, src_y, src_w, src_h);
ret = drm_atomic_helper_check_plane_state(&state, crtc->state, &clip, 0,
ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, 0,
INT_MAX, true, false);
if (ret)
return ret;

View File

@ -30,7 +30,8 @@ config DRM_DUMB_VGA_DAC
depends on OF
select DRM_KMS_HELPER
help
Support for RGB to VGA DAC based bridges
Support for non-programmable RGB to VGA DAC bridges, such as ADI
ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs.
config DRM_LVDS_ENCODER
tristate "Transparent parallel to LVDS encoder support"

View File

@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
return 0;
}
int analogix_dp_psr_supported(struct device *dev)
int analogix_dp_psr_supported(struct analogix_dp_device *dp)
{
struct analogix_dp_device *dp = dev_get_drvdata(dev);
return dp->psr_support;
}
EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
int analogix_dp_enable_psr(struct device *dev)
int analogix_dp_enable_psr(struct analogix_dp_device *dp)
{
struct analogix_dp_device *dp = dev_get_drvdata(dev);
struct edp_vsc_psr psr_vsc;
if (!dp->psr_support)
@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev)
}
EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
int analogix_dp_disable_psr(struct device *dev)
int analogix_dp_disable_psr(struct analogix_dp_device *dp)
{
struct analogix_dp_device *dp = dev_get_drvdata(dev);
struct edp_vsc_psr psr_vsc;
int ret;
@ -1015,28 +1012,31 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge)
{
struct analogix_dp_device *dp = bridge->driver_private;
struct drm_encoder *encoder = dp->encoder;
struct drm_connector *connector = &dp->connector;
int ret;
struct drm_connector *connector = NULL;
int ret = 0;
if (!bridge->encoder) {
DRM_ERROR("Parent encoder object not found");
return -ENODEV;
}
connector->polled = DRM_CONNECTOR_POLL_HPD;
if (!dp->plat_data->skip_connector) {
connector = &dp->connector;
connector->polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(dp->drm_dev, connector,
&analogix_dp_connector_funcs,
DRM_MODE_CONNECTOR_eDP);
if (ret) {
DRM_ERROR("Failed to initialize connector with drm\n");
return ret;
ret = drm_connector_init(dp->drm_dev, connector,
&analogix_dp_connector_funcs,
DRM_MODE_CONNECTOR_eDP);
if (ret) {
DRM_ERROR("Failed to initialize connector with drm\n");
return ret;
}
drm_connector_helper_add(connector,
&analogix_dp_connector_helper_funcs);
drm_mode_connector_attach_encoder(connector, encoder);
}
drm_connector_helper_add(connector,
&analogix_dp_connector_helper_funcs);
drm_mode_connector_attach_encoder(connector, encoder);
/*
* NOTE: the connector registration is implemented in analogix
* platform driver, that to say connector would be exist after
@ -1279,8 +1279,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
return analogix_dp_transfer(dp, msg);
}
int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
struct analogix_dp_plat_data *plat_data)
struct analogix_dp_device *
analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
struct analogix_dp_plat_data *plat_data)
{
struct platform_device *pdev = to_platform_device(dev);
struct analogix_dp_device *dp;
@ -1290,14 +1291,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
if (!plat_data) {
dev_err(dev, "Invalided input plat_data\n");
return -EINVAL;
return ERR_PTR(-EINVAL);
}
dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
if (!dp)
return -ENOMEM;
dev_set_drvdata(dev, dp);
return ERR_PTR(-ENOMEM);
dp->dev = &pdev->dev;
dp->dpms_mode = DRM_MODE_DPMS_OFF;
@ -1314,7 +1313,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
ret = analogix_dp_dt_parse_pdata(dp);
if (ret)
return ret;
return ERR_PTR(ret);
dp->phy = devm_phy_get(dp->dev, "dp");
if (IS_ERR(dp->phy)) {
@ -1328,14 +1327,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
if (ret == -ENOSYS || ret == -ENODEV)
dp->phy = NULL;
else
return ret;
return ERR_PTR(ret);
}
}
dp->clock = devm_clk_get(&pdev->dev, "dp");
if (IS_ERR(dp->clock)) {
dev_err(&pdev->dev, "failed to get clock\n");
return PTR_ERR(dp->clock);
return ERR_CAST(dp->clock);
}
clk_prepare_enable(dp->clock);
@ -1344,7 +1343,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dp->reg_base))
return PTR_ERR(dp->reg_base);
return ERR_CAST(dp->reg_base);
dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
@ -1365,7 +1364,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
"hpd_gpio");
if (ret) {
dev_err(&pdev->dev, "failed to get hpd gpio\n");
return ret;
return ERR_PTR(ret);
}
dp->irq = gpio_to_irq(dp->hpd_gpio);
irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@ -1377,16 +1376,9 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
if (dp->irq == -ENXIO) {
dev_err(&pdev->dev, "failed to get irq\n");
return -ENODEV;
return ERR_PTR(-ENODEV);
}
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
phy_power_on(dp->phy);
analogix_dp_init_dp(dp);
ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
analogix_dp_hardirq,
analogix_dp_irq_thread,
@ -1406,38 +1398,30 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
ret = drm_dp_aux_register(&dp->aux);
if (ret)
goto err_disable_pm_runtime;
return ERR_PTR(ret);
pm_runtime_enable(dev);
ret = analogix_dp_create_bridge(drm_dev, dp);
if (ret) {
DRM_ERROR("failed to create bridge (%d)\n", ret);
drm_encoder_cleanup(dp->encoder);
goto err_disable_pm_runtime;
}
phy_power_off(dp->phy);
pm_runtime_put(dev);
return 0;
return dp;
err_disable_pm_runtime:
phy_power_off(dp->phy);
pm_runtime_put(dev);
pm_runtime_disable(dev);
return ret;
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(analogix_dp_bind);
void analogix_dp_unbind(struct device *dev, struct device *master,
void *data)
void analogix_dp_unbind(struct analogix_dp_device *dp)
{
struct analogix_dp_device *dp = dev_get_drvdata(dev);
analogix_dp_bridge_disable(dp->bridge);
dp->connector.funcs->destroy(&dp->connector);
dp->encoder->funcs->destroy(dp->encoder);
if (dp->plat_data->panel) {
if (drm_panel_unprepare(dp->plat_data->panel))
@ -1447,16 +1431,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master,
}
drm_dp_aux_unregister(&dp->aux);
pm_runtime_disable(dev);
pm_runtime_disable(dp->dev);
clk_disable_unprepare(dp->clock);
}
EXPORT_SYMBOL_GPL(analogix_dp_unbind);
#ifdef CONFIG_PM
int analogix_dp_suspend(struct device *dev)
int analogix_dp_suspend(struct analogix_dp_device *dp)
{
struct analogix_dp_device *dp = dev_get_drvdata(dev);
clk_disable_unprepare(dp->clock);
if (dp->plat_data->panel) {
@ -1468,9 +1450,8 @@ int analogix_dp_suspend(struct device *dev)
}
EXPORT_SYMBOL_GPL(analogix_dp_suspend);
int analogix_dp_resume(struct device *dev)
int analogix_dp_resume(struct analogix_dp_device *dp)
{
struct analogix_dp_device *dp = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(dp->clock);

View File

@ -137,7 +137,9 @@ static int sii902x_get_modes(struct drm_connector *connector)
struct sii902x *sii902x = connector_to_sii902x(connector);
struct regmap *regmap = sii902x->regmap;
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
struct device *dev = &sii902x->i2c->dev;
unsigned long timeout;
unsigned int retries;
unsigned int status;
struct edid *edid;
int num = 0;
@ -159,7 +161,7 @@ static int sii902x_get_modes(struct drm_connector *connector)
time_before(jiffies, timeout));
if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus\n");
dev_err(dev, "failed to acquire the i2c bus\n");
return -ETIMEDOUT;
}
@ -179,9 +181,19 @@ static int sii902x_get_modes(struct drm_connector *connector)
if (ret)
return ret;
ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
/*
* Sometimes the I2C bus can stall after failure to use the
* EDID channel. Retry a few times to see if things clear
* up, else continue anyway.
*/
retries = 5;
do {
ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA,
&status);
retries--;
} while (ret && retries);
if (ret)
return ret;
dev_err(dev, "failed to read status (%d)\n", ret);
ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
SII902X_SYS_CTRL_DDC_BUS_REQ |
@ -201,7 +213,7 @@ static int sii902x_get_modes(struct drm_connector *connector)
if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
dev_err(&sii902x->i2c->dev, "failed to release the i2c bus\n");
dev_err(dev, "failed to release the i2c bus\n");
return -ETIMEDOUT;
}

View File

@ -1654,6 +1654,8 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
* (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
* as needing the workaround, with 4 iterations for v1.30a and 1
* iteration for others.
* The Amlogic Meson GX SoCs (v2.01a) have been identified as needing
* the workaround with a single iteration.
*/
switch (hdmi->version) {
@ -1662,6 +1664,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
break;
case 0x131a:
case 0x132a:
case 0x201a:
count = 1;
break;
default:

View File

@ -342,7 +342,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
val, !(val & GEN_CMD_FULL), 1000,
CMD_PKT_STATUS_TIMEOUT_US);
if (ret < 0) {
if (ret) {
dev_err(dsi->dev, "failed to get available command FIFO\n");
return ret;
}
@ -353,7 +353,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
val, (val & mask) == mask,
1000, CMD_PKT_STATUS_TIMEOUT_US);
if (ret < 0) {
if (ret) {
dev_err(dsi->dev, "failed to write command FIFO\n");
return ret;
}
@ -385,7 +385,7 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
val, !(val & GEN_PLD_W_FULL), 1000,
CMD_PKT_STATUS_TIMEOUT_US);
if (ret < 0) {
if (ret) {
dev_err(dsi->dev,
"failed to get available write payload FIFO\n");
return ret;
@ -721,13 +721,13 @@ static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi)
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val,
val & PHY_LOCK, 1000, PHY_STATUS_TIMEOUT_US);
if (ret < 0)
if (ret)
DRM_DEBUG_DRIVER("failed to wait phy lock state\n");
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
val, val & PHY_STOP_STATE_CLK_LANE, 1000,
PHY_STATUS_TIMEOUT_US);
if (ret < 0)
if (ret)
DRM_DEBUG_DRIVER("failed to wait phy clk lane stop state\n");
}

View File

@ -759,6 +759,10 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
state->rotation = val;
} else if (property == plane->zpos_property) {
state->zpos = val;
} else if (property == plane->color_encoding_property) {
state->color_encoding = val;
} else if (property == plane->color_range_property) {
state->color_range = val;
} else if (plane->funcs->atomic_set_property) {
return plane->funcs->atomic_set_property(plane, state,
property, val);
@ -818,6 +822,10 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
*val = state->rotation;
} else if (property == plane->zpos_property) {
*val = state->zpos;
} else if (property == plane->color_encoding_property) {
*val = state->color_encoding;
} else if (property == plane->color_range_property) {
*val = state->color_range;
} else if (plane->funcs->atomic_get_property) {
return plane->funcs->atomic_get_property(plane, state, property, val);
} else {
@ -882,12 +890,14 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
}
/* Check whether this plane supports the fb pixel format. */
ret = drm_plane_check_pixel_format(plane, state->fb->format->format);
ret = drm_plane_check_pixel_format(plane, state->fb->format->format,
state->fb->modifier);
if (ret) {
struct drm_format_name_buf format_name;
DRM_DEBUG_ATOMIC("Invalid pixel format %s\n",
drm_get_format_name(state->fb->format->format,
&format_name));
DRM_DEBUG_ATOMIC("Invalid pixel format %s, modifier 0x%llx\n",
drm_get_format_name(state->fb->format->format,
&format_name),
state->fb->modifier);
return ret;
}
@ -944,6 +954,10 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest));
drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src));
drm_printf(p, "\trotation=%x\n", state->rotation);
drm_printf(p, "\tcolor-encoding=%s\n",
drm_get_color_encoding_name(state->color_encoding));
drm_printf(p, "\tcolor-range=%s\n",
drm_get_color_range_name(state->color_range));
if (plane->funcs->atomic_print_state)
plane->funcs->atomic_print_state(p, state);

View File

@ -699,7 +699,6 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
* drm_atomic_helper_check_plane_state() - Check plane state for validity
* @plane_state: plane state to check
* @crtc_state: crtc state to check
* @clip: integer clipping coordinates
* @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
* @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
* @can_position: is it legal to position the plane such that it
@ -719,7 +718,6 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
*/
int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
const struct drm_crtc_state *crtc_state,
const struct drm_rect *clip,
int min_scale,
int max_scale,
bool can_position,
@ -729,6 +727,7 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
struct drm_rect *src = &plane_state->src;
struct drm_rect *dst = &plane_state->dst;
unsigned int rotation = plane_state->rotation;
struct drm_rect clip = {};
int hscale, vscale;
WARN_ON(plane_state->crtc && plane_state->crtc != crtc_state->crtc);
@ -764,7 +763,10 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
return -ERANGE;
}
plane_state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode, &clip.x2, &clip.y2);
plane_state->visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale);
drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
@ -778,10 +780,10 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
*/
return 0;
if (!can_position && !drm_rect_equals(dst, clip)) {
if (!can_position && !drm_rect_equals(dst, &clip)) {
DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
drm_rect_debug_print("dst: ", dst, false);
drm_rect_debug_print("clip: ", clip, false);
drm_rect_debug_print("clip: ", &clip, false);
return -EINVAL;
}

View File

@ -88,6 +88,20 @@
* drm_mode_crtc_set_gamma_size(). Drivers which support both should use
* drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the
* "GAMMA_LUT" property above.
*
* Support for different non RGB color encodings is controlled through
* &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They
* are set up by calling drm_plane_create_color_properties().
*
* "COLOR_ENCODING"
* Optional plane enum property to support different non RGB
* color encodings. The driver can provide a subset of standard
* enum values supported by the DRM plane.
*
* "COLOR_RANGE"
* Optional plane enum property to support different non RGB
* color parameter ranges. The driver can provide a subset of
* standard enum values supported by the DRM plane.
*/
/**
@ -339,3 +353,122 @@ out:
drm_modeset_unlock(&crtc->mutex);
return ret;
}
static const char * const color_encoding_name[] = {
[DRM_COLOR_YCBCR_BT601] = "ITU-R BT.601 YCbCr",
[DRM_COLOR_YCBCR_BT709] = "ITU-R BT.709 YCbCr",
[DRM_COLOR_YCBCR_BT2020] = "ITU-R BT.2020 YCbCr",
};
static const char * const color_range_name[] = {
[DRM_COLOR_YCBCR_FULL_RANGE] = "YCbCr full range",
[DRM_COLOR_YCBCR_LIMITED_RANGE] = "YCbCr limited range",
};
/**
* drm_get_color_encoding_name - return a string for color encoding
* @encoding: color encoding to compute name of
*
* In contrast to the other drm_get_*_name functions this one here returns a
* const pointer and hence is threadsafe.
*/
const char *drm_get_color_encoding_name(enum drm_color_encoding encoding)
{
if (WARN_ON(encoding >= ARRAY_SIZE(color_encoding_name)))
return "unknown";
return color_encoding_name[encoding];
}
/**
* drm_get_color_range_name - return a string for color range
* @range: color range to compute name of
*
* In contrast to the other drm_get_*_name functions this one here returns a
* const pointer and hence is threadsafe.
*/
const char *drm_get_color_range_name(enum drm_color_range range)
{
if (WARN_ON(range >= ARRAY_SIZE(color_range_name)))
return "unknown";
return color_range_name[range];
}
/**
* drm_plane_create_color_properties - color encoding related plane properties
* @plane: plane object
* @supported_encodings: bitfield indicating supported color encodings
* @supported_ranges: bitfileld indicating supported color ranges
* @default_encoding: default color encoding
* @default_range: default color range
*
* Create and attach plane specific COLOR_ENCODING and COLOR_RANGE
* properties to @plane. The supported encodings and ranges should
* be provided in supported_encodings and supported_ranges bitmasks.
* Each bit set in the bitmask indicates that its number as enum
* value is supported.
*/
int drm_plane_create_color_properties(struct drm_plane *plane,
u32 supported_encodings,
u32 supported_ranges,
enum drm_color_encoding default_encoding,
enum drm_color_range default_range)
{
struct drm_device *dev = plane->dev;
struct drm_property *prop;
struct drm_prop_enum_list enum_list[max(DRM_COLOR_ENCODING_MAX,
DRM_COLOR_RANGE_MAX)];
int i, len;
if (WARN_ON(supported_encodings == 0 ||
(supported_encodings & -BIT(DRM_COLOR_ENCODING_MAX)) != 0 ||
(supported_encodings & BIT(default_encoding)) == 0))
return -EINVAL;
if (WARN_ON(supported_ranges == 0 ||
(supported_ranges & -BIT(DRM_COLOR_RANGE_MAX)) != 0 ||
(supported_ranges & BIT(default_range)) == 0))
return -EINVAL;
len = 0;
for (i = 0; i < DRM_COLOR_ENCODING_MAX; i++) {
if ((supported_encodings & BIT(i)) == 0)
continue;
enum_list[len].type = i;
enum_list[len].name = color_encoding_name[i];
len++;
}
prop = drm_property_create_enum(dev, 0, "COLOR_ENCODING",
enum_list, len);
if (!prop)
return -ENOMEM;
plane->color_encoding_property = prop;
drm_object_attach_property(&plane->base, prop, default_encoding);
if (plane->state)
plane->state->color_encoding = default_encoding;
len = 0;
for (i = 0; i < DRM_COLOR_RANGE_MAX; i++) {
if ((supported_ranges & BIT(i)) == 0)
continue;
enum_list[len].type = i;
enum_list[len].name = color_range_name[i];
len++;
}
prop = drm_property_create_enum(dev, 0, "COLOR_RANGE",
enum_list, len);
if (!prop)
return -ENOMEM;
plane->color_range_property = prop;
drm_object_attach_property(&plane->base, prop, default_range);
if (plane->state)
plane->state->color_range = default_range;
return 0;
}
EXPORT_SYMBOL(drm_plane_create_color_properties);

View File

@ -629,12 +629,14 @@ retry:
*/
if (!crtc->primary->format_default) {
ret = drm_plane_check_pixel_format(crtc->primary,
fb->format->format);
fb->format->format,
fb->modifier);
if (ret) {
struct drm_format_name_buf format_name;
DRM_DEBUG_KMS("Invalid pixel format %s\n",
drm_get_format_name(fb->format->format,
&format_name));
DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n",
drm_get_format_name(fb->format->format,
&format_name),
fb->modifier);
goto out;
}
}

View File

@ -71,6 +71,8 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
/* drm_color_mgmt.c */
const char *drm_get_color_encoding_name(enum drm_color_encoding encoding);
const char *drm_get_color_range_name(enum drm_color_range range);
/* IOCTLs */
int drm_mode_gamma_get_ioctl(struct drm_device *dev,
@ -196,8 +198,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
/* drm_plane.c */
int drm_plane_register_all(struct drm_device *dev);
void drm_plane_unregister_all(struct drm_device *dev);
int drm_plane_check_pixel_format(const struct drm_plane *plane,
u32 format);
int drm_plane_check_pixel_format(struct drm_plane *plane,
u32 format, u64 modifier);
/* drm_bridge.c */
void drm_bridge_detach(struct drm_bridge *bridge);

View File

@ -99,7 +99,7 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
case DRM_MINOR_CONTROL:
return &dev->control;
default:
return NULL;
BUG();
}
}

View File

@ -153,7 +153,7 @@ EXPORT_SYMBOL(drm_legacy_ioremapfree);
u64 drm_get_max_iomem(void)
{
struct resource *tmp;
u64 max_iomem = 0;
resource_size_t max_iomem = 0;
for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) {
max_iomem = max(max_iomem, tmp->end);

View File

@ -180,7 +180,7 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node,
struct drm_mm *mm = hole_node->mm;
struct rb_node **link, *rb;
struct drm_mm_node *parent;
bool leftmost = true;
bool leftmost;
node->__subtree_last = LAST(node);
@ -201,6 +201,7 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node,
} else {
rb = NULL;
link = &mm->interval_tree.rb_root.rb_node;
leftmost = true;
}
while (*link) {
@ -208,11 +209,11 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node,
parent = rb_entry(rb, struct drm_mm_node, rb);
if (parent->__subtree_last < node->__subtree_last)
parent->__subtree_last = node->__subtree_last;
if (node->start < parent->start)
if (node->start < parent->start) {
link = &parent->rb.rb_left;
else {
} else {
link = &parent->rb.rb_right;
leftmost = true;
leftmost = false;
}
}

View File

@ -113,6 +113,7 @@ retry:
kfree(ctx);
return;
}
ww_acquire_done(&ctx->ww_ctx);
WARN_ON(config->acquire_ctx);

View File

@ -122,12 +122,10 @@ int drm_of_component_probe(struct device *dev,
if (!port)
break;
if (!of_device_is_available(port->parent)) {
of_node_put(port);
continue;
}
if (of_device_is_available(port->parent))
drm_of_component_match_add(dev, &match, compare_of,
port);
drm_of_component_match_add(dev, &match, compare_of, port);
of_node_put(port);
}

View File

@ -11,6 +11,7 @@
#include <linux/dmi.h>
#include <linux/module.h>
#include <drm/drm_connector.h>
#include <drm/drm_utils.h>
#ifdef CONFIG_DMI

View File

@ -549,16 +549,33 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
return 0;
}
int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
int drm_plane_check_pixel_format(struct drm_plane *plane,
u32 format, u64 modifier)
{
unsigned int i;
for (i = 0; i < plane->format_count; i++) {
if (format == plane->format_types[i])
return 0;
break;
}
if (i == plane->format_count)
return -EINVAL;
return -EINVAL;
if (!plane->modifier_count)
return 0;
for (i = 0; i < plane->modifier_count; i++) {
if (modifier == plane->modifiers[i])
break;
}
if (i == plane->modifier_count)
return -EINVAL;
if (plane->funcs->format_mod_supported &&
!plane->funcs->format_mod_supported(plane, format, modifier))
return -EINVAL;
return 0;
}
/*
@ -602,12 +619,14 @@ static int __setplane_internal(struct drm_plane *plane,
}
/* Check whether this plane supports the fb pixel format. */
ret = drm_plane_check_pixel_format(plane, fb->format->format);
ret = drm_plane_check_pixel_format(plane, fb->format->format,
fb->modifier);
if (ret) {
struct drm_format_name_buf format_name;
DRM_DEBUG_KMS("Invalid pixel format %s\n",
drm_get_format_name(fb->format->format,
&format_name));
DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n",
drm_get_format_name(fb->format->format,
&format_name),
fb->modifier);
goto out;
}

View File

@ -106,7 +106,6 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
* @fb: framebuffer to flip onto plane
* @src: source coordinates in 16.16 fixed point
* @dst: integer destination coordinates
* @clip: integer clipping coordinates
* @rotation: plane rotation
* @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
* @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
@ -131,7 +130,6 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
struct drm_framebuffer *fb,
struct drm_rect *src,
struct drm_rect *dst,
const struct drm_rect *clip,
unsigned int rotation,
int min_scale,
int max_scale,
@ -157,11 +155,12 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
struct drm_crtc_state crtc_state = {
.crtc = crtc,
.enable = crtc->enabled,
.mode = crtc->mode,
};
int ret;
ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
clip, min_scale, max_scale,
min_scale, max_scale,
can_position,
can_update_disabled);
if (ret)
@ -239,16 +238,12 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
.x2 = crtc_x + crtc_w,
.y2 = crtc_y + crtc_h,
};
const struct drm_rect clip = {
.x2 = crtc->mode.hdisplay,
.y2 = crtc->mode.vdisplay,
};
struct drm_connector **connector_list;
int num_connectors, ret;
bool visible;
ret = drm_plane_helper_check_update(plane, crtc, fb,
&src, &dest, &clip,
&src, &dest,
DRM_MODE_ROTATE_0,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,

View File

@ -230,26 +230,26 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
struct drm_prime_attachment *prime_attach = attach->priv;
struct drm_gem_object *obj = dma_buf->priv;
struct drm_device *dev = obj->dev;
struct sg_table *sgt;
if (prime_attach) {
struct sg_table *sgt = prime_attach->sgt;
if (sgt) {
if (prime_attach->dir != DMA_NONE)
dma_unmap_sg_attrs(attach->dev, sgt->sgl,
sgt->nents,
prime_attach->dir,
DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sgt);
}
kfree(sgt);
kfree(prime_attach);
attach->priv = NULL;
}
if (dev->driver->gem_prime_unpin)
dev->driver->gem_prime_unpin(obj);
if (!prime_attach)
return;
sgt = prime_attach->sgt;
if (sgt) {
if (prime_attach->dir != DMA_NONE)
dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents,
prime_attach->dir,
DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sgt);
}
kfree(sgt);
kfree(prime_attach);
attach->priv = NULL;
}
EXPORT_SYMBOL(drm_gem_map_detach);
@ -922,40 +922,40 @@ EXPORT_SYMBOL(drm_prime_pages_to_sg);
/**
* drm_prime_sg_to_page_addr_arrays - convert an sg table into a page array
* @sgt: scatter-gather table to convert
* @pages: array of page pointers to store the page array in
* @pages: optional array of page pointers to store the page array in
* @addrs: optional array to store the dma bus address of each page
* @max_pages: size of both the passed-in arrays
* @max_entries: size of both the passed-in arrays
*
* Exports an sg table into an array of pages and addresses. This is currently
* required by the TTM driver in order to do correct fault handling.
*/
int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
dma_addr_t *addrs, int max_pages)
dma_addr_t *addrs, int max_entries)
{
unsigned count;
struct scatterlist *sg;
struct page *page;
u32 len;
int pg_index;
u32 len, index;
dma_addr_t addr;
pg_index = 0;
index = 0;
for_each_sg(sgt->sgl, sg, sgt->nents, count) {
len = sg->length;
page = sg_page(sg);
addr = sg_dma_address(sg);
while (len > 0) {
if (WARN_ON(pg_index >= max_pages))
if (WARN_ON(index >= max_entries))
return -1;
pages[pg_index] = page;
if (pages)
pages[index] = page;
if (addrs)
addrs[pg_index] = addr;
addrs[index] = addr;
page++;
addr += PAGE_SIZE;
len -= PAGE_SIZE;
pg_index++;
index++;
}
}
return 0;

View File

@ -50,11 +50,27 @@
* IOCTL and in the get/set property IOCTL.
*/
static bool drm_property_type_valid(struct drm_property *property)
static bool drm_property_flags_valid(u32 flags)
{
if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
u32 legacy_type = flags & DRM_MODE_PROP_LEGACY_TYPE;
u32 ext_type = flags & DRM_MODE_PROP_EXTENDED_TYPE;
/* Reject undefined/deprecated flags */
if (flags & ~(DRM_MODE_PROP_LEGACY_TYPE |
DRM_MODE_PROP_EXTENDED_TYPE |
DRM_MODE_PROP_IMMUTABLE |
DRM_MODE_PROP_ATOMIC))
return false;
/* We want either a legacy type or an extended type, but not both */
if (!legacy_type == !ext_type)
return false;
/* Only one legacy type at a time please */
if (legacy_type && !is_power_of_2(legacy_type))
return false;
return true;
}
/**
@ -72,12 +88,19 @@ static bool drm_property_type_valid(struct drm_property *property)
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create(struct drm_device *dev, int flags,
const char *name, int num_values)
struct drm_property *drm_property_create(struct drm_device *dev,
u32 flags, const char *name,
int num_values)
{
struct drm_property *property = NULL;
int ret;
if (WARN_ON(!drm_property_flags_valid(flags)))
return NULL;
if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
return NULL;
property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
if (!property)
return NULL;
@ -99,15 +122,11 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
property->num_values = num_values;
INIT_LIST_HEAD(&property->enum_list);
if (name) {
strncpy(property->name, name, DRM_PROP_NAME_LEN);
property->name[DRM_PROP_NAME_LEN-1] = '\0';
}
strncpy(property->name, name, DRM_PROP_NAME_LEN);
property->name[DRM_PROP_NAME_LEN-1] = '\0';
list_add_tail(&property->head, &dev->mode_config.property_list);
WARN_ON(!drm_property_type_valid(property));
return property;
fail:
kfree(property->values);
@ -135,10 +154,10 @@ EXPORT_SYMBOL(drm_property_create);
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
const char *name,
const struct drm_prop_enum_list *props,
int num_values)
struct drm_property *drm_property_create_enum(struct drm_device *dev,
u32 flags, const char *name,
const struct drm_prop_enum_list *props,
int num_values)
{
struct drm_property *property;
int i, ret;
@ -184,10 +203,10 @@ EXPORT_SYMBOL(drm_property_create_enum);
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
int flags, const char *name,
const struct drm_prop_enum_list *props,
int num_props,
uint64_t supported_bits)
u32 flags, const char *name,
const struct drm_prop_enum_list *props,
int num_props,
uint64_t supported_bits)
{
struct drm_property *property;
int i, ret, index = 0;
@ -221,8 +240,8 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
EXPORT_SYMBOL(drm_property_create_bitmask);
static struct drm_property *property_create_range(struct drm_device *dev,
int flags, const char *name,
uint64_t min, uint64_t max)
u32 flags, const char *name,
uint64_t min, uint64_t max)
{
struct drm_property *property;
@ -255,9 +274,9 @@ static struct drm_property *property_create_range(struct drm_device *dev,
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
const char *name,
uint64_t min, uint64_t max)
struct drm_property *drm_property_create_range(struct drm_device *dev,
u32 flags, const char *name,
uint64_t min, uint64_t max)
{
return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
name, min, max);
@ -284,8 +303,8 @@ EXPORT_SYMBOL(drm_property_create_range);
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
int flags, const char *name,
int64_t min, int64_t max)
u32 flags, const char *name,
int64_t min, int64_t max)
{
return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
name, I642U64(min), I642U64(max));
@ -311,7 +330,7 @@ EXPORT_SYMBOL(drm_property_create_signed_range);
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_object(struct drm_device *dev,
int flags, const char *name,
u32 flags, const char *name,
uint32_t type)
{
struct drm_property *property;
@ -347,8 +366,8 @@ EXPORT_SYMBOL(drm_property_create_object);
* Returns:
* A pointer to the newly created property on success, NULL on failure.
*/
struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
const char *name)
struct drm_property *drm_property_create_bool(struct drm_device *dev,
u32 flags, const char *name)
{
return drm_property_create_range(dev, flags, name, 0, 1);
}
@ -374,26 +393,24 @@ int drm_property_add_enum(struct drm_property *property, int index,
{
struct drm_property_enum *prop_enum;
if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
return -EINVAL;
if (WARN_ON(!drm_property_type_is(property, DRM_MODE_PROP_ENUM) &&
!drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
return -EINVAL;
/*
* Bitmask enum properties have the additional constraint of values
* from 0 to 63
*/
if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
(value > 63))
if (WARN_ON(drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
value > 63))
return -EINVAL;
if (!list_empty(&property->enum_list)) {
list_for_each_entry(prop_enum, &property->enum_list, head) {
if (prop_enum->value == value) {
strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
return 0;
}
}
list_for_each_entry(prop_enum, &property->enum_list, head) {
if (WARN_ON(prop_enum->value == value))
return -EINVAL;
}
prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);

View File

@ -92,6 +92,28 @@ static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
.atomic_disable = drm_simple_kms_crtc_disable,
};
static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct drm_simple_display_pipe *pipe;
pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
if (!pipe->funcs || !pipe->funcs->enable_vblank)
return 0;
return pipe->funcs->enable_vblank(pipe);
}
static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct drm_simple_display_pipe *pipe;
pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
if (!pipe->funcs || !pipe->funcs->disable_vblank)
return;
pipe->funcs->disable_vblank(pipe);
}
static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.destroy = drm_crtc_cleanup,
@ -99,12 +121,13 @@ static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
.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,
.enable_vblank = drm_simple_kms_crtc_enable_vblank,
.disable_vblank = drm_simple_kms_crtc_disable_vblank,
};
static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *plane_state)
{
struct drm_rect clip = { 0 };
struct drm_simple_display_pipe *pipe;
struct drm_crtc_state *crtc_state;
int ret;
@ -112,15 +135,8 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
pipe = container_of(plane, struct drm_simple_display_pipe, plane);
crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
&pipe->crtc);
if (!crtc_state->enable)
return 0; /* nothing to check when disabling or disabled */
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
&clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, true);
@ -128,7 +144,7 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
return ret;
if (!plane_state->visible)
return -EINVAL;
return 0;
if (!pipe->funcs || !pipe->funcs->check)
return 0;

View File

@ -120,6 +120,9 @@ static u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe)
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
if (WARN_ON(!crtc))
return 0;
if (crtc->funcs->get_vblank_counter)
return crtc->funcs->get_vblank_counter(crtc);
}
@ -318,6 +321,9 @@ static void __disable_vblank(struct drm_device *dev, unsigned int pipe)
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
if (WARN_ON(!crtc))
return;
if (crtc->funcs->disable_vblank) {
crtc->funcs->disable_vblank(crtc);
return;
@ -920,6 +926,9 @@ static int __enable_vblank(struct drm_device *dev, unsigned int pipe)
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
if (WARN_ON(!crtc))
return 0;
if (crtc->funcs->enable_vblank)
return crtc->funcs->enable_vblank(crtc);
}

View File

@ -41,6 +41,7 @@ struct exynos_dp_device {
struct device *dev;
struct videomode vm;
struct analogix_dp_device *adp;
struct analogix_dp_plat_data plat_data;
};
@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
struct drm_device *drm_dev = data;
int ret;
/*
* Just like the probe function said, we don't need the
* device drvrate anymore, we should leave the charge to
* analogix dp driver, set the device drvdata to NULL.
*/
dev_set_drvdata(dev, NULL);
dp->dev = dev;
dp->drm_dev = drm_dev;
@ -190,13 +184,22 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
dp->plat_data.encoder = encoder;
return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
if (IS_ERR(dp->adp)) {
dp->encoder.funcs->destroy(&dp->encoder);
return PTR_ERR(dp->adp);
}
return 0;
}
static void exynos_dp_unbind(struct device *dev, struct device *master,
void *data)
{
return analogix_dp_unbind(dev, master, data);
struct exynos_dp_device *dp = dev_get_drvdata(dev);
analogix_dp_unbind(dp->adp);
dp->encoder.funcs->destroy(&dp->encoder);
}
static const struct component_ops exynos_dp_ops = {
@ -241,6 +244,7 @@ static int exynos_dp_probe(struct platform_device *pdev)
/* The remote port can be either a panel or a bridge */
dp->plat_data.panel = panel;
dp->plat_data.skip_connector = !!bridge;
dp->ptn_bridge = bridge;
out:
@ -257,12 +261,16 @@ static int exynos_dp_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int exynos_dp_suspend(struct device *dev)
{
return analogix_dp_suspend(dev);
struct exynos_dp_device *dp = dev_get_drvdata(dev);
return analogix_dp_suspend(dp->adp);
}
static int exynos_dp_resume(struct device *dev)
{
return analogix_dp_resume(dev);
struct exynos_dp_device *dp = dev_get_drvdata(dev);
return analogix_dp_resume(dp->adp);
}
#endif

View File

@ -6132,6 +6132,7 @@ enum {
#define _DVSACNTR 0x72180
#define DVS_ENABLE (1<<31)
#define DVS_GAMMA_ENABLE (1<<30)
#define DVS_YUV_RANGE_CORRECTION_DISABLE (1<<27)
#define DVS_PIXFORMAT_MASK (3<<25)
#define DVS_FORMAT_YUV422 (0<<25)
#define DVS_FORMAT_RGBX101010 (1<<25)
@ -6140,6 +6141,7 @@ enum {
#define DVS_PIPE_CSC_ENABLE (1<<24)
#define DVS_SOURCE_KEY (1<<22)
#define DVS_RGB_ORDER_XBGR (1<<20)
#define DVS_YUV_FORMAT_BT709 (1<<18)
#define DVS_YUV_BYTE_ORDER_MASK (3<<16)
#define DVS_YUV_ORDER_YUYV (0<<16)
#define DVS_YUV_ORDER_UYVY (1<<16)
@ -6199,6 +6201,7 @@ enum {
#define _SPRA_CTL 0x70280
#define SPRITE_ENABLE (1<<31)
#define SPRITE_GAMMA_ENABLE (1<<30)
#define SPRITE_YUV_RANGE_CORRECTION_DISABLE (1<<28)
#define SPRITE_PIXFORMAT_MASK (7<<25)
#define SPRITE_FORMAT_YUV422 (0<<25)
#define SPRITE_FORMAT_RGBX101010 (1<<25)
@ -6210,7 +6213,7 @@ enum {
#define SPRITE_SOURCE_KEY (1<<22)
#define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */
#define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19)
#define SPRITE_YUV_CSC_FORMAT_BT709 (1<<18) /* 0 is BT601 */
#define SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709 (1<<18) /* 0 is BT601 */
#define SPRITE_YUV_BYTE_ORDER_MASK (3<<16)
#define SPRITE_YUV_ORDER_YUYV (0<<16)
#define SPRITE_YUV_ORDER_UYVY (1<<16)
@ -6286,6 +6289,7 @@ enum {
#define SP_FORMAT_RGBA8888 (0xf<<26)
#define SP_ALPHA_PREMULTIPLY (1<<23) /* CHV pipe B */
#define SP_SOURCE_KEY (1<<22)
#define SP_YUV_FORMAT_BT709 (1<<18)
#define SP_YUV_BYTE_ORDER_MASK (3<<16)
#define SP_YUV_ORDER_YUYV (0<<16)
#define SP_YUV_ORDER_UYVY (1<<16)
@ -6305,6 +6309,12 @@ enum {
#define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4)
#define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8)
#define SP_CONST_ALPHA_ENABLE (1<<31)
#define _SPACLRC0 (VLV_DISPLAY_BASE + 0x721d0)
#define SP_CONTRAST(x) ((x) << 18) /* u3.6 */
#define SP_BRIGHTNESS(x) ((x) & 0xff) /* s8 */
#define _SPACLRC1 (VLV_DISPLAY_BASE + 0x721d4)
#define SP_SH_SIN(x) (((x) & 0x7ff) << 16) /* s4.7 */
#define SP_SH_COS(x) (x) /* u3.7 */
#define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4)
#define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280)
@ -6318,6 +6328,8 @@ enum {
#define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0)
#define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4)
#define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8)
#define _SPBCLRC0 (VLV_DISPLAY_BASE + 0x722d0)
#define _SPBCLRC1 (VLV_DISPLAY_BASE + 0x722d4)
#define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4)
#define _MMIO_VLV_SPR(pipe, plane_id, reg_a, reg_b) \
@ -6334,6 +6346,8 @@ enum {
#define SPKEYMAXVAL(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPAKEYMAXVAL, _SPBKEYMAXVAL)
#define SPTILEOFF(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPATILEOFF, _SPBTILEOFF)
#define SPCONSTALPHA(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACONSTALPHA, _SPBCONSTALPHA)
#define SPCLRC0(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC0, _SPBCLRC0)
#define SPCLRC1(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC1, _SPBCLRC1)
#define SPGAMC(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPAGAMC, _SPBGAMC)
/*
@ -6379,6 +6393,7 @@ enum {
#define _PLANE_CTL_3_A 0x70380
#define PLANE_CTL_ENABLE (1 << 31)
#define PLANE_CTL_PIPE_GAMMA_ENABLE (1 << 30) /* Pre-GLK */
#define PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE (1 << 28)
/*
* ICL+ uses the same PLANE_CTL_FORMAT bits, but the field definition
* expanded to include bit 23 as well. However, the shift-24 based values
@ -6400,6 +6415,7 @@ enum {
#define PLANE_CTL_KEY_ENABLE_DESTINATION ( 2 << 21)
#define PLANE_CTL_ORDER_BGRX (0 << 20)
#define PLANE_CTL_ORDER_RGBX (1 << 20)
#define PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709 (1 << 18)
#define PLANE_CTL_YUV422_ORDER_MASK (0x3 << 16)
#define PLANE_CTL_YUV422_YUYV ( 0 << 16)
#define PLANE_CTL_YUV422_UYVY ( 1 << 16)
@ -6452,7 +6468,13 @@ enum {
#define _PLANE_COLOR_CTL_2_A 0x702CC /* GLK+ */
#define _PLANE_COLOR_CTL_3_A 0x703CC /* GLK+ */
#define PLANE_COLOR_PIPE_GAMMA_ENABLE (1 << 30)
#define PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE (1 << 28)
#define PLANE_COLOR_PIPE_CSC_ENABLE (1 << 23)
#define PLANE_COLOR_CSC_MODE_BYPASS (0 << 17)
#define PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709 (1 << 17)
#define PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709 (2 << 17)
#define PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020 (3 << 17)
#define PLANE_COLOR_CSC_MODE_RGB709_TO_RGB2020 (4 << 17)
#define PLANE_COLOR_PLANE_GAMMA_DISABLE (1 << 13)
#define PLANE_COLOR_ALPHA_MASK (0x3 << 4)
#define PLANE_COLOR_ALPHA_DISABLE (0 << 4)

View File

@ -3083,9 +3083,6 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
struct intel_crtc *crtc = to_intel_crtc(plane_state->base.crtc);
const struct drm_framebuffer *fb = plane_state->base.fb;
int src_x = plane_state->base.src.x1 >> 16;
int src_y = plane_state->base.src.y1 >> 16;
@ -3095,11 +3092,6 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
int y = src_y / vsub;
u32 offset;
if (!skl_plane_has_ccs(dev_priv, crtc->pipe, plane->id)) {
DRM_DEBUG_KMS("No RC support on %s\n", plane->base.name);
return -EINVAL;
}
if (plane_state->base.rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180)) {
DRM_DEBUG_KMS("RC support only with 0/180 degree rotation %x\n",
plane_state->base.rotation);
@ -3564,6 +3556,12 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
PLANE_CTL_PIPE_GAMMA_ENABLE |
PLANE_CTL_PIPE_CSC_ENABLE |
PLANE_CTL_PLANE_GAMMA_DISABLE;
if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709;
if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE;
}
plane_ctl |= skl_plane_ctl_format(fb->format->format);
@ -3593,6 +3591,16 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format);
if (intel_format_is_yuv(fb->format->format)) {
if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709;
else
plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV601_TO_RGB709;
if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
}
return plane_color_ctl;
}
@ -9389,18 +9397,12 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
struct drm_rect clip = {};
int src_x, src_y;
u32 offset;
int ret;
if (crtc_state->base.enable)
drm_mode_get_hv_timing(&crtc_state->base.mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(&plane_state->base,
&crtc_state->base,
&clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);
@ -12839,7 +12841,6 @@ intel_check_primary_plane(struct intel_plane *plane,
int min_scale = DRM_PLANE_HELPER_NO_SCALING;
int max_scale = DRM_PLANE_HELPER_NO_SCALING;
bool can_position = false;
struct drm_rect clip = {};
int ret;
if (INTEL_GEN(dev_priv) >= 9) {
@ -12851,13 +12852,8 @@ intel_check_primary_plane(struct intel_plane *plane,
can_position = true;
}
if (crtc_state->base.enable)
drm_mode_get_hv_timing(&crtc_state->base.mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(&state->base,
&crtc_state->base,
&clip,
min_scale, max_scale,
can_position, true);
if (ret)
@ -13338,6 +13334,15 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
DRM_MODE_ROTATE_0,
supported_rotations);
if (INTEL_GEN(dev_priv) >= 9)
drm_plane_create_color_properties(&primary->base,
BIT(DRM_COLOR_YCBCR_BT601) |
BIT(DRM_COLOR_YCBCR_BT709),
BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
BIT(DRM_COLOR_YCBCR_FULL_RANGE),
DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE);
drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
return primary;

View File

@ -1596,6 +1596,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
u32 glk_color_ctl(const struct intel_plane_state *plane_state);
u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
unsigned int rotation);
int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
@ -2021,6 +2022,7 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
/* intel_sprite.c */
bool intel_format_is_yuv(u32 format);
int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
int usecs);
struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv,

View File

@ -41,8 +41,7 @@
#include <drm/i915_drm.h>
#include "i915_drv.h"
static bool
format_is_yuv(uint32_t format)
bool intel_format_is_yuv(u32 format)
{
switch (format) {
case DRM_FORMAT_YUYV:
@ -266,6 +265,7 @@ skl_update_plane(struct intel_plane *plane,
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id),
plane_state->color_ctl);
if (key->flags) {
I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value);
@ -346,44 +346,103 @@ skl_plane_get_hw_state(struct intel_plane *plane)
}
static void
chv_update_csc(struct intel_plane *plane, uint32_t format)
chv_update_csc(const struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
enum plane_id plane_id = plane->id;
/*
* |r| | c0 c1 c2 | |cr|
* |g| = | c3 c4 c5 | x |y |
* |b| | c6 c7 c8 | |cb|
*
* Coefficients are s3.12.
*
* Cb and Cr apparently come in as signed already, and
* we always get full range data in on account of CLRC0/1.
*/
static const s16 csc_matrix[][9] = {
/* BT.601 full range YCbCr -> full range RGB */
[DRM_COLOR_YCBCR_BT601] = {
5743, 4096, 0,
-2925, 4096, -1410,
0, 4096, 7258,
},
/* BT.709 full range YCbCr -> full range RGB */
[DRM_COLOR_YCBCR_BT709] = {
6450, 4096, 0,
-1917, 4096, -767,
0, 4096, 7601,
},
};
const s16 *csc = csc_matrix[plane_state->base.color_encoding];
/* Seems RGB data bypasses the CSC always */
if (!format_is_yuv(format))
if (!intel_format_is_yuv(fb->format->format))
return;
/*
* BT.601 limited range YCbCr -> full range RGB
*
* |r| | 6537 4769 0| |cr |
* |g| = |-3330 4769 -1605| x |y-64|
* |b| | 0 4769 8263| |cb |
*
* Cb and Cr apparently come in as signed already, so no
* need for any offset. For Y we need to remove the offset.
*/
I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(-64));
I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4769) | SPCSC_C0(6537));
I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-3330) | SPCSC_C0(0));
I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1605) | SPCSC_C0(4769));
I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4769) | SPCSC_C0(0));
I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(8263));
I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(csc[1]) | SPCSC_C0(csc[0]));
I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(csc[3]) | SPCSC_C0(csc[2]));
I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(csc[5]) | SPCSC_C0(csc[4]));
I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(csc[7]) | SPCSC_C0(csc[6]));
I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(csc[8]));
I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(940) | SPCSC_IMIN(64));
I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(1023) | SPCSC_IMIN(0));
I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512));
I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512));
I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
}
#define SIN_0 0
#define COS_0 1
static void
vlv_update_clrc(const struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
enum pipe pipe = plane->pipe;
enum plane_id plane_id = plane->id;
int contrast, brightness, sh_scale, sh_sin, sh_cos;
if (intel_format_is_yuv(fb->format->format) &&
plane_state->base.color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) {
/*
* Expand limited range to full range:
* Contrast is applied first and is used to expand Y range.
* Brightness is applied second and is used to remove the
* offset from Y. Saturation/hue is used to expand CbCr range.
*/
contrast = DIV_ROUND_CLOSEST(255 << 6, 235 - 16);
brightness = -DIV_ROUND_CLOSEST(16 * 255, 235 - 16);
sh_scale = DIV_ROUND_CLOSEST(128 << 7, 240 - 128);
sh_sin = SIN_0 * sh_scale;
sh_cos = COS_0 * sh_scale;
} else {
/* Pass-through everything. */
contrast = 1 << 6;
brightness = 0;
sh_scale = 1 << 7;
sh_sin = SIN_0 * sh_scale;
sh_cos = COS_0 * sh_scale;
}
/* FIXME these register are single buffered :( */
I915_WRITE_FW(SPCLRC0(pipe, plane_id),
SP_CONTRAST(contrast) | SP_BRIGHTNESS(brightness));
I915_WRITE_FW(SPCLRC1(pipe, plane_id),
SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos));
}
static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
@ -433,6 +492,9 @@ static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
return 0;
}
if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
sprctl |= SP_YUV_FORMAT_BT709;
if (fb->modifier == I915_FORMAT_MOD_X_TILED)
sprctl |= SP_TILED;
@ -477,8 +539,10 @@ vlv_update_plane(struct intel_plane *plane,
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
vlv_update_clrc(plane_state);
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
chv_update_csc(plane, fb->format->format);
chv_update_csc(plane_state);
if (key->flags) {
I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value);
@ -584,6 +648,12 @@ static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
return 0;
}
if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709;
if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
sprctl |= SPRITE_YUV_RANGE_CORRECTION_DISABLE;
if (fb->modifier == I915_FORMAT_MOD_X_TILED)
sprctl |= SPRITE_TILED;
@ -740,6 +810,12 @@ static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,
return 0;
}
if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
dvscntr |= DVS_YUV_FORMAT_BT709;
if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
dvscntr |= DVS_YUV_RANGE_CORRECTION_DISABLE;
if (fb->modifier == I915_FORMAT_MOD_X_TILED)
dvscntr |= DVS_TILED;
@ -979,7 +1055,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
src_y = src->y1 >> 16;
src_h = drm_rect_height(src) >> 16;
if (format_is_yuv(fb->format->format)) {
if (intel_format_is_yuv(fb->format->format)) {
src_x &= ~1;
src_w &= ~1;
@ -1459,6 +1535,14 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
DRM_MODE_ROTATE_0,
supported_rotations);
drm_plane_create_color_properties(&intel_plane->base,
BIT(DRM_COLOR_YCBCR_BT601) |
BIT(DRM_COLOR_YCBCR_BT709),
BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
BIT(DRM_COLOR_YCBCR_FULL_RANGE),
DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE);
drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
return intel_plane;

View File

@ -351,7 +351,6 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
struct drm_framebuffer *old_fb = old_state->fb;
unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
struct drm_rect clip = {};
int hsub, vsub;
int ret;
@ -367,11 +366,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
if (WARN_ON(!crtc_state))
return -EINVAL;
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
can_position, true);

View File

@ -91,7 +91,6 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
{
struct drm_framebuffer *fb = state->fb;
struct drm_crtc_state *crtc_state;
struct drm_rect clip = { 0, };
if (!fb)
return 0;
@ -108,11 +107,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
return drm_atomic_helper_check_plane_state(state, crtc_state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);

View File

@ -49,7 +49,6 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct drm_crtc_state *crtc_state;
struct drm_rect clip = { 0, };
if (!state->crtc)
return 0;
@ -58,11 +57,7 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
return drm_atomic_helper_check_plane_state(state, crtc_state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);

View File

@ -286,7 +286,6 @@ static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state,
uint32_t max_width, max_height;
bool out_of_bounds = false;
uint32_t caps = 0;
struct drm_rect clip = {};
int min_scale, max_scale;
int ret;
@ -323,11 +322,7 @@ static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state,
min_scale = FRAC_16_16(1, 8);
max_scale = FRAC_16_16(8, 1);
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
min_scale, max_scale,
true, true);
if (ret)
@ -471,7 +466,6 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
{
struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
struct drm_crtc_state *crtc_state;
struct drm_rect clip = {};
int min_scale, max_scale;
int ret;
@ -502,11 +496,7 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
min_scale = FRAC_16_16(1, 8);
max_scale = FRAC_16_16(8, 1);
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
min_scale, max_scale,
true, true);
if (ret)

View File

@ -131,11 +131,37 @@ static int mxsfb_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
return drm_gem_fb_prepare_fb(&pipe->plane, plane_state);
}
static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
{
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
/* Clear and enable VBLANK IRQ */
mxsfb_enable_axi_clk(mxsfb);
writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
mxsfb_disable_axi_clk(mxsfb);
return 0;
}
static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe)
{
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
/* Disable and clear VBLANK IRQ */
mxsfb_enable_axi_clk(mxsfb);
writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
mxsfb_disable_axi_clk(mxsfb);
}
static struct drm_simple_display_pipe_funcs mxsfb_funcs = {
.enable = mxsfb_pipe_enable,
.disable = mxsfb_pipe_disable,
.update = mxsfb_pipe_update,
.prepare_fb = mxsfb_pipe_prepare_fb,
.enable_vblank = mxsfb_pipe_enable_vblank,
.disable_vblank = mxsfb_pipe_disable_vblank,
};
static int mxsfb_load(struct drm_device *drm, unsigned long flags)
@ -274,33 +300,11 @@ static void mxsfb_lastclose(struct drm_device *drm)
drm_fbdev_cma_restore_mode(mxsfb->fbdev);
}
static int mxsfb_enable_vblank(struct drm_device *drm, unsigned int crtc)
{
struct mxsfb_drm_private *mxsfb = drm->dev_private;
/* Clear and enable VBLANK IRQ */
mxsfb_enable_axi_clk(mxsfb);
writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
mxsfb_disable_axi_clk(mxsfb);
return 0;
}
static void mxsfb_disable_vblank(struct drm_device *drm, unsigned int crtc)
{
struct mxsfb_drm_private *mxsfb = drm->dev_private;
/* Disable and clear VBLANK IRQ */
mxsfb_enable_axi_clk(mxsfb);
writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
mxsfb_disable_axi_clk(mxsfb);
}
static void mxsfb_irq_preinstall(struct drm_device *drm)
{
mxsfb_disable_vblank(drm, 0);
struct mxsfb_drm_private *mxsfb = drm->dev_private;
mxsfb_pipe_disable_vblank(&mxsfb->pipe);
}
static irqreturn_t mxsfb_irq_handler(int irq, void *data)
@ -333,8 +337,6 @@ static struct drm_driver mxsfb_driver = {
.irq_handler = mxsfb_irq_handler,
.irq_preinstall = mxsfb_irq_preinstall,
.irq_uninstall = mxsfb_irq_preinstall,
.enable_vblank = mxsfb_enable_vblank,
.disable_vblank = mxsfb_disable_vblank,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = drm_gem_cma_dumb_create,

View File

@ -46,7 +46,6 @@ struct nouveau_plane {
struct drm_property *brightness;
struct drm_property *hue;
struct drm_property *saturation;
struct drm_property *iturbt_709;
} props;
int colorkey;
@ -54,7 +53,7 @@ struct nouveau_plane {
int brightness;
int hue;
int saturation;
int iturbt_709;
enum drm_color_encoding color_encoding;
void (*set_params)(struct nouveau_plane *);
};
@ -166,7 +165,7 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (fb->format->format == DRM_FORMAT_NV12 ||
fb->format->format == DRM_FORMAT_NV21)
format |= NV_PVIDEO_FORMAT_PLANAR;
if (nv_plane->iturbt_709)
if (nv_plane->color_encoding == DRM_COLOR_YCBCR_BT709)
format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
if (nv_plane->colorkey & (1 << 24))
format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;
@ -229,7 +228,7 @@ nv10_set_params(struct nouveau_plane *plane)
nvif_wr32(dev, NV_PVIDEO_COLOR_KEY, plane->colorkey & 0xffffff);
if (plane->cur) {
if (plane->iturbt_709)
if (plane->color_encoding == DRM_COLOR_YCBCR_BT709)
format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
if (plane->colorkey & (1 << 24))
format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;
@ -258,8 +257,8 @@ nv_set_property(struct drm_plane *plane,
nv_plane->hue = value;
else if (property == nv_plane->props.saturation)
nv_plane->saturation = value;
else if (property == nv_plane->props.iturbt_709)
nv_plane->iturbt_709 = value;
else if (property == nv_plane->base.color_encoding_property)
nv_plane->color_encoding = value;
else
return -EINVAL;
@ -313,14 +312,11 @@ nv10_overlay_init(struct drm_device *device)
device, 0, "hue", 0, 359);
plane->props.saturation = drm_property_create_range(
device, 0, "saturation", 0, 8192 - 1);
plane->props.iturbt_709 = drm_property_create_range(
device, 0, "iturbt_709", 0, 1);
if (!plane->props.colorkey ||
!plane->props.contrast ||
!plane->props.brightness ||
!plane->props.hue ||
!plane->props.saturation ||
!plane->props.iturbt_709)
!plane->props.saturation)
goto cleanup;
plane->colorkey = 0;
@ -343,9 +339,13 @@ nv10_overlay_init(struct drm_device *device)
drm_object_attach_property(&plane->base.base,
plane->props.saturation, plane->saturation);
plane->iturbt_709 = 0;
drm_object_attach_property(&plane->base.base,
plane->props.iturbt_709, plane->iturbt_709);
plane->color_encoding = DRM_COLOR_YCBCR_BT601;
drm_plane_create_color_properties(&plane->base,
BIT(DRM_COLOR_YCBCR_BT601) |
BIT(DRM_COLOR_YCBCR_BT709),
BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
DRM_COLOR_YCBCR_BT601,
DRM_COLOR_YCBCR_LIMITED_RANGE);
plane->set_params = nv10_set_params;
nv10_set_params(plane);

View File

@ -1143,15 +1143,9 @@ static int
nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
struct drm_rect clip = {};
int ret;
if (asyh->state.enable)
drm_mode_get_hv_timing(&asyh->state.mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
&clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);
@ -1435,18 +1429,12 @@ nv50_base_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
struct nv50_head_atom *asyh)
{
const struct drm_framebuffer *fb = asyw->state.fb;
struct drm_rect clip = {};
int ret;
if (!fb->format->depth)
return -EINVAL;
if (asyh->state.enable)
drm_mode_get_hv_timing(&asyh->state.mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
&clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, true);

View File

@ -132,7 +132,7 @@ static const struct versatile_panel_type versatile_panels[] = {
.width_mm = 79,
.height_mm = 54,
.mode = {
.clock = 10000000,
.clock = 10000,
.hdisplay = 320,
.hsync_start = 320 + 6,
.hsync_end = 320 + 6 + 6,
@ -156,7 +156,7 @@ static const struct versatile_panel_type versatile_panels[] = {
.width_mm = 171,
.height_mm = 130,
.mode = {
.clock = 25000000,
.clock = 25000,
.hdisplay = 640,
.hsync_start = 640 + 24,
.hsync_end = 640 + 24 + 96,
@ -179,7 +179,7 @@ static const struct versatile_panel_type versatile_panels[] = {
.width_mm = 34,
.height_mm = 45,
.mode = {
.clock = 625000000,
.clock = 62500,
.hdisplay = 176,
.hsync_start = 176 + 2,
.hsync_end = 176 + 2 + 3,
@ -203,7 +203,7 @@ static const struct versatile_panel_type versatile_panels[] = {
.width_mm = 37,
.height_mm = 50,
.mode = {
.clock = 5400000,
.clock = 5400,
.hdisplay = 240,
.hsync_start = 240 + 10,
.hsync_end = 240 + 10 + 10,

View File

@ -8,7 +8,6 @@ config DRM_PL111
select DRM_GEM_CMA_HELPER
select DRM_BRIDGE
select DRM_PANEL_BRIDGE
select DRM_DUMB_VGA_DAC
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
help
Choose this option for DRM support for the PL111 CLCD controller.

View File

@ -50,6 +50,41 @@ irqreturn_t pl111_irq(int irq, void *data)
return status;
}
static enum drm_mode_status
pl111_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
struct drm_device *drm = crtc->dev;
struct pl111_drm_dev_private *priv = drm->dev_private;
u32 cpp = priv->variant->fb_bpp / 8;
u64 bw;
/*
* We use the pixelclock to also account for interlaced modes, the
* resulting bandwidth is in bytes per second.
*/
bw = mode->clock * 1000; /* In Hz */
bw = bw * mode->hdisplay * mode->vdisplay * cpp;
bw = div_u64(bw, mode->htotal * mode->vtotal);
/*
* If no bandwidth constraints, anything goes, else
* check if we are too fast.
*/
if (priv->memory_bw && (bw > priv->memory_bw)) {
DRM_DEBUG_KMS("%d x %d @ %d Hz, %d cpp, bw %llu too fast\n",
mode->hdisplay, mode->vdisplay,
mode->clock * 1000, cpp, bw);
return MODE_BAD;
}
DRM_DEBUG_KMS("%d x %d @ %d Hz, %d cpp, bw %llu bytes/s OK\n",
mode->hdisplay, mode->vdisplay,
mode->clock * 1000, cpp, bw);
return MODE_OK;
}
static int pl111_display_check(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *pstate,
struct drm_crtc_state *cstate)
@ -321,8 +356,10 @@ static void pl111_display_update(struct drm_simple_display_pipe *pipe,
}
}
int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc)
static int pl111_display_enable_vblank(struct drm_simple_display_pipe *pipe)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct pl111_drm_dev_private *priv = drm->dev_private;
writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + priv->ienb);
@ -330,8 +367,10 @@ int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc)
return 0;
}
void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc)
static void pl111_display_disable_vblank(struct drm_simple_display_pipe *pipe)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct pl111_drm_dev_private *priv = drm->dev_private;
writel(0, priv->regs + priv->ienb);
@ -343,7 +382,8 @@ static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe,
return drm_gem_fb_prepare_fb(&pipe->plane, plane_state);
}
static const struct drm_simple_display_pipe_funcs pl111_display_funcs = {
static struct drm_simple_display_pipe_funcs pl111_display_funcs = {
.mode_valid = pl111_mode_valid,
.check = pl111_display_check,
.enable = pl111_display_enable,
.disable = pl111_display_disable,
@ -502,6 +542,11 @@ int pl111_display_init(struct drm_device *drm)
if (ret)
return ret;
if (!priv->variant->broken_vblank) {
pl111_display_funcs.enable_vblank = pl111_display_enable_vblank;
pl111_display_funcs.disable_vblank = pl111_display_disable_vblank;
}
ret = drm_simple_display_pipe_init(drm, &priv->pipe,
&pl111_display_funcs,
priv->variant->formats,

View File

@ -43,6 +43,7 @@ struct drm_minor;
* @broken_vblank: the vblank IRQ is broken on this variant
* @formats: array of supported pixel formats on this variant
* @nformats: the length of the array of supported pixel formats
* @fb_bpp: desired bits per pixel on the default framebuffer
*/
struct pl111_variant_data {
const char *name;
@ -52,6 +53,7 @@ struct pl111_variant_data {
bool broken_vblank;
const u32 *formats;
unsigned int nformats;
unsigned int fb_bpp;
};
struct pl111_drm_dev_private {
@ -63,6 +65,7 @@ struct pl111_drm_dev_private {
struct drm_simple_display_pipe pipe;
void *regs;
u32 memory_bw;
u32 ienb;
u32 ctrl;
/* The pixel clock (a reference to our clock divider off of CLCDCLK). */
@ -79,8 +82,6 @@ struct pl111_drm_dev_private {
};
int pl111_display_init(struct drm_device *dev);
int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc);
void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc);
irqreturn_t pl111_irq(int irq, void *data);
int pl111_debugfs_init(struct drm_minor *minor);

View File

@ -192,7 +192,7 @@ static int pl111_modeset_init(struct drm_device *dev)
drm_mode_config_reset(dev);
drm_fb_cma_fbdev_init(dev, 32, 0);
drm_fb_cma_fbdev_init(dev, priv->variant->fb_bpp, 0);
drm_kms_helper_poll_init(dev);
@ -249,11 +249,6 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
if (!priv)
return -ENOMEM;
if (!variant->broken_vblank) {
pl111_drm_driver.enable_vblank = pl111_enable_vblank;
pl111_drm_driver.disable_vblank = pl111_disable_vblank;
}
drm = drm_dev_alloc(&pl111_drm_driver, dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
@ -262,6 +257,12 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
drm->dev_private = priv;
priv->variant = variant;
if (of_property_read_u32(dev->of_node, "max-memory-bandwidth",
&priv->memory_bw)) {
dev_info(dev, "no max memory bandwidth specified, assume unlimited\n");
priv->memory_bw = 0;
}
/* The two variants swap this register */
if (variant->is_pl110) {
priv->ienb = CLCD_PL110_IENB;
@ -341,6 +342,7 @@ static const struct pl111_variant_data pl110_variant = {
.is_pl110 = true,
.formats = pl110_pixel_formats,
.nformats = ARRAY_SIZE(pl110_pixel_formats),
.fb_bpp = 16,
};
/* RealView, Versatile Express etc use this modern variant */
@ -365,6 +367,7 @@ static const struct pl111_variant_data pl111_variant = {
.name = "PL111",
.formats = pl111_pixel_formats,
.nformats = ARRAY_SIZE(pl111_pixel_formats),
.fb_bpp = 32,
};
static const struct amba_id pl111_id_table[] = {

View File

@ -230,6 +230,23 @@ static const u32 pl110_versatile_pixel_formats[] = {
DRM_FORMAT_XRGB1555,
};
static const u32 pl111_realview_pixel_formats[] = {
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_BGR565,
DRM_FORMAT_RGB565,
DRM_FORMAT_ABGR1555,
DRM_FORMAT_XBGR1555,
DRM_FORMAT_ARGB1555,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_ABGR4444,
DRM_FORMAT_XBGR4444,
DRM_FORMAT_ARGB4444,
DRM_FORMAT_XRGB4444,
};
/*
* The Integrator variant is a PL110 with a bunch of broken, or not
* yet implemented features
@ -241,6 +258,7 @@ static const struct pl111_variant_data pl110_integrator = {
.broken_vblank = true,
.formats = pl110_integrator_pixel_formats,
.nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),
.fb_bpp = 16,
};
/*
@ -253,6 +271,19 @@ static const struct pl111_variant_data pl110_versatile = {
.external_bgr = true,
.formats = pl110_versatile_pixel_formats,
.nformats = ARRAY_SIZE(pl110_versatile_pixel_formats),
.fb_bpp = 16,
};
/*
* RealView PL111 variant, the only real difference from the vanilla
* PL111 is that we select 16bpp framebuffer by default to be able
* to get 1024x768 without saturating the memory bus.
*/
static const struct pl111_variant_data pl111_realview = {
.name = "PL111 RealView",
.formats = pl111_realview_pixel_formats,
.nformats = ARRAY_SIZE(pl111_realview_pixel_formats),
.fb_bpp = 16,
};
int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
@ -304,6 +335,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
case REALVIEW_CLCD_PBA8:
case REALVIEW_CLCD_PBX:
versatile_syscon_map = map;
priv->variant = &pl111_realview;
priv->variant_display_enable = pl111_realview_clcd_enable;
priv->variant_display_disable = pl111_realview_clcd_disable;
dev_info(dev, "set up callbacks for RealView PL111\n");

View File

@ -572,7 +572,6 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane,
{
struct drm_device *dev = plane->dev;
struct drm_crtc_state *crtc_state;
struct drm_rect clip = {};
int ret;
if (!state->crtc) {
@ -589,11 +588,7 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane,
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);

View File

@ -77,6 +77,7 @@ struct rockchip_dp_device {
const struct rockchip_dp_chip_data *data;
struct analogix_dp_device *adp;
struct analogix_dp_plat_data plat_data;
};
@ -84,7 +85,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
{
struct rockchip_dp_device *dp = to_dp(encoder);
if (!analogix_dp_psr_supported(dp->dev))
if (!analogix_dp_psr_supported(dp->adp))
return;
DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
@ -114,9 +115,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
mutex_lock(&dp->psr_lock);
if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
analogix_dp_enable_psr(dp->dev);
analogix_dp_enable_psr(dp->adp);
else
analogix_dp_disable_psr(dp->dev);
analogix_dp_disable_psr(dp->adp);
mutex_unlock(&dp->psr_lock);
}
@ -149,12 +150,17 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
return ret;
}
return 0;
return rockchip_drm_psr_activate(&dp->encoder);
}
static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
{
struct rockchip_dp_device *dp = to_dp(plat_data);
int ret;
ret = rockchip_drm_psr_deactivate(&dp->encoder);
if (ret != 0)
return ret;
clk_disable_unprepare(dp->pclk);
@ -258,13 +264,8 @@ static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = {
.atomic_check = rockchip_dp_drm_encoder_atomic_check,
};
static void rockchip_dp_drm_encoder_destroy(struct drm_encoder *encoder)
{
drm_encoder_cleanup(encoder);
}
static struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
.destroy = rockchip_dp_drm_encoder_destroy,
.destroy = drm_encoder_cleanup,
};
static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
@ -334,13 +335,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
struct drm_device *drm_dev = data;
int ret;
/*
* Just like the probe function said, we don't need the
* device drvrate anymore, we should leave the charge to
* analogix dp driver, set the device drvdata to NULL.
*/
dev_set_drvdata(dev, NULL);
dp_data = of_device_get_match_data(dev);
if (!dp_data)
return -ENODEV;
@ -365,9 +359,22 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
INIT_WORK(&dp->psr_work, analogix_dp_psr_work);
rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
if (ret < 0)
goto err_cleanup_encoder;
return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
if (IS_ERR(dp->adp)) {
ret = PTR_ERR(dp->adp);
goto err_unreg_psr;
}
return 0;
err_unreg_psr:
rockchip_drm_psr_unregister(&dp->encoder);
err_cleanup_encoder:
dp->encoder.funcs->destroy(&dp->encoder);
return ret;
}
static void rockchip_dp_unbind(struct device *dev, struct device *master,
@ -375,9 +382,9 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
analogix_dp_unbind(dp->adp);
rockchip_drm_psr_unregister(&dp->encoder);
analogix_dp_unbind(dev, master, data);
dp->encoder.funcs->destroy(&dp->encoder);
}
static const struct component_ops rockchip_dp_component_ops = {
@ -407,11 +414,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
/*
* We just use the drvdata until driver run into component
* add function, and then we would set drvdata to null, so
* that analogix dp driver could take charge of the drvdata.
*/
platform_set_drvdata(pdev, dp);
return component_add(dev, &rockchip_dp_component_ops);
@ -424,10 +426,26 @@ static int rockchip_dp_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rockchip_dp_suspend(struct device *dev)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
return analogix_dp_suspend(dp->adp);
}
static int rockchip_dp_resume(struct device *dev)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
return analogix_dp_resume(dp->adp);
}
#endif
static const struct dev_pm_ops rockchip_dp_pm_ops = {
#ifdef CONFIG_PM_SLEEP
.suspend = analogix_dp_suspend,
.resume_early = analogix_dp_resume,
.suspend = rockchip_dp_suspend,
.resume_early = rockchip_dp_resume,
#endif
};

View File

@ -1302,8 +1302,8 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
err_mipi_dsi_host:
mipi_dsi_host_unregister(&dsi->dsi_host);
err_cleanup:
drm_encoder_cleanup(&dsi->encoder);
drm_connector_cleanup(&dsi->connector);
dsi->connector.funcs->destroy(&dsi->connector);
dsi->encoder.funcs->destroy(&dsi->encoder);
err_pllref:
clk_disable_unprepare(dsi->pllref_clk);
return ret;
@ -1316,6 +1316,10 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
mipi_dsi_host_unregister(&dsi->dsi_host);
pm_runtime_disable(dev);
dsi->connector.funcs->destroy(&dsi->connector);
dsi->encoder.funcs->destroy(&dsi->encoder);
clk_disable_unprepare(dsi->pllref_clk);
}

View File

@ -165,7 +165,6 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
{
struct device_node *np = hdmi->dev->of_node;
int ret;
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(hdmi->regmap)) {
@ -193,13 +192,6 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
return PTR_ERR(hdmi->grf_clk);
}
ret = clk_prepare_enable(hdmi->vpll_clk);
if (ret) {
DRM_DEV_ERROR(hdmi->dev,
"Failed to enable HDMI vpll: %d\n", ret);
return ret;
}
return 0;
}
@ -374,6 +366,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
return ret;
}
ret = clk_prepare_enable(hdmi->vpll_clk);
if (ret) {
DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
ret);
return ret;
}
drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
@ -389,6 +388,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
if (IS_ERR(hdmi->hdmi)) {
ret = PTR_ERR(hdmi->hdmi);
drm_encoder_cleanup(encoder);
clk_disable_unprepare(hdmi->vpll_clk);
}
return ret;
@ -400,6 +400,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
dw_hdmi_unbind(hdmi->hdmi);
clk_disable_unprepare(hdmi->vpll_clk);
}
static const struct component_ops dw_hdmi_rockchip_ops = {

View File

@ -849,8 +849,10 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
if (irq < 0) {
ret = irq;
goto err_disable_clk;
}
inno_hdmi_reset(hdmi);
@ -858,7 +860,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
if (IS_ERR(hdmi->ddc)) {
ret = PTR_ERR(hdmi->ddc);
hdmi->ddc = NULL;
return ret;
goto err_disable_clk;
}
/*
@ -872,7 +874,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
ret = inno_hdmi_register(drm, hdmi);
if (ret)
return ret;
goto err_put_adapter;
dev_set_drvdata(dev, hdmi);
@ -882,7 +884,17 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
inno_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret < 0)
goto err_cleanup_hdmi;
return 0;
err_cleanup_hdmi:
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
err_put_adapter:
i2c_put_adapter(hdmi->ddc);
err_disable_clk:
clk_disable_unprepare(hdmi->pclk);
return ret;
}
@ -894,8 +906,8 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master,
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
clk_disable_unprepare(hdmi->pclk);
i2c_put_adapter(hdmi->ddc);
clk_disable_unprepare(hdmi->pclk);
}
static const struct component_ops inno_hdmi_ops = {

View File

@ -134,7 +134,7 @@ static int rockchip_drm_bind(struct device *dev)
drm_dev->dev_private = private;
INIT_LIST_HEAD(&private->psr_list);
spin_lock_init(&private->psr_list_lock);
mutex_init(&private->psr_list_lock);
ret = rockchip_drm_init_iommu(drm_dev);
if (ret)
@ -314,6 +314,14 @@ static int compare_dev(struct device *dev, void *data)
return dev == (struct device *)data;
}
static void rockchip_drm_match_remove(struct device *dev)
{
struct device_link *link;
list_for_each_entry(link, &dev->links.consumers, s_node)
device_link_del(link);
}
static struct component_match *rockchip_drm_match_add(struct device *dev)
{
struct component_match *match = NULL;
@ -331,10 +339,15 @@ static struct component_match *rockchip_drm_match_add(struct device *dev)
if (!d)
break;
device_link_add(dev, d, DL_FLAG_STATELESS);
component_match_add(dev, &match, compare_dev, d);
} while (true);
}
if (IS_ERR(match))
rockchip_drm_match_remove(dev);
return match ?: ERR_PTR(-ENODEV);
}
@ -411,13 +424,21 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev)
if (IS_ERR(match))
return PTR_ERR(match);
return component_master_add_with_match(dev, &rockchip_drm_ops, match);
ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
if (ret < 0) {
rockchip_drm_match_remove(dev);
return ret;
}
return 0;
}
static int rockchip_drm_platform_remove(struct platform_device *pdev)
{
component_master_del(&pdev->dev, &rockchip_drm_ops);
rockchip_drm_match_remove(&pdev->dev);
return 0;
}

View File

@ -55,7 +55,7 @@ struct rockchip_drm_private {
struct mutex mm_lock;
struct drm_mm mm;
struct list_head psr_list;
spinlock_t psr_list_lock;
struct mutex psr_list_lock;
};
int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,

View File

@ -18,7 +18,7 @@
#include "rockchip_drm_drv.h"
#include "rockchip_drm_psr.h"
#define PSR_FLUSH_TIMEOUT msecs_to_jiffies(100)
#define PSR_FLUSH_TIMEOUT_MS 100
enum psr_state {
PSR_FLUSH,
@ -30,11 +30,11 @@ struct psr_drv {
struct list_head list;
struct drm_encoder *encoder;
spinlock_t lock;
struct mutex lock;
bool active;
enum psr_state state;
struct timer_list flush_timer;
struct delayed_work flush_work;
void (*set)(struct drm_encoder *encoder, bool enable);
};
@ -43,9 +43,8 @@ static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc)
{
struct rockchip_drm_private *drm_drv = crtc->dev->dev_private;
struct psr_drv *psr;
unsigned long flags;
spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
mutex_lock(&drm_drv->psr_list_lock);
list_for_each_entry(psr, &drm_drv->psr_list, list) {
if (psr->encoder->crtc == crtc)
goto out;
@ -53,7 +52,24 @@ static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc)
psr = ERR_PTR(-ENODEV);
out:
spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
mutex_unlock(&drm_drv->psr_list_lock);
return psr;
}
static struct psr_drv *find_psr_by_encoder(struct drm_encoder *encoder)
{
struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
struct psr_drv *psr;
mutex_lock(&drm_drv->psr_list_lock);
list_for_each_entry(psr, &drm_drv->psr_list, list) {
if (psr->encoder == encoder)
goto out;
}
psr = ERR_PTR(-ENODEV);
out:
mutex_unlock(&drm_drv->psr_list_lock);
return psr;
}
@ -94,43 +110,40 @@ static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state)
static void psr_set_state(struct psr_drv *psr, enum psr_state state)
{
unsigned long flags;
spin_lock_irqsave(&psr->lock, flags);
mutex_lock(&psr->lock);
psr_set_state_locked(psr, state);
spin_unlock_irqrestore(&psr->lock, flags);
mutex_unlock(&psr->lock);
}
static void psr_flush_handler(struct timer_list *t)
static void psr_flush_handler(struct work_struct *work)
{
struct psr_drv *psr = from_timer(psr, t, flush_timer);
unsigned long flags;
struct psr_drv *psr = container_of(to_delayed_work(work),
struct psr_drv, flush_work);
/* If the state has changed since we initiated the flush, do nothing */
spin_lock_irqsave(&psr->lock, flags);
mutex_lock(&psr->lock);
if (psr->state == PSR_FLUSH)
psr_set_state_locked(psr, PSR_ENABLE);
spin_unlock_irqrestore(&psr->lock, flags);
mutex_unlock(&psr->lock);
}
/**
* rockchip_drm_psr_activate - activate PSR on the given pipe
* @crtc: CRTC to obtain the PSR encoder
* @encoder: encoder to obtain the PSR encoder
*
* Returns:
* Zero on success, negative errno on failure.
*/
int rockchip_drm_psr_activate(struct drm_crtc *crtc)
int rockchip_drm_psr_activate(struct drm_encoder *encoder)
{
struct psr_drv *psr = find_psr_by_crtc(crtc);
unsigned long flags;
struct psr_drv *psr = find_psr_by_encoder(encoder);
if (IS_ERR(psr))
return PTR_ERR(psr);
spin_lock_irqsave(&psr->lock, flags);
mutex_lock(&psr->lock);
psr->active = true;
spin_unlock_irqrestore(&psr->lock, flags);
mutex_unlock(&psr->lock);
return 0;
}
@ -138,23 +151,22 @@ EXPORT_SYMBOL(rockchip_drm_psr_activate);
/**
* rockchip_drm_psr_deactivate - deactivate PSR on the given pipe
* @crtc: CRTC to obtain the PSR encoder
* @encoder: encoder to obtain the PSR encoder
*
* Returns:
* Zero on success, negative errno on failure.
*/
int rockchip_drm_psr_deactivate(struct drm_crtc *crtc)
int rockchip_drm_psr_deactivate(struct drm_encoder *encoder)
{
struct psr_drv *psr = find_psr_by_crtc(crtc);
unsigned long flags;
struct psr_drv *psr = find_psr_by_encoder(encoder);
if (IS_ERR(psr))
return PTR_ERR(psr);
spin_lock_irqsave(&psr->lock, flags);
mutex_lock(&psr->lock);
psr->active = false;
spin_unlock_irqrestore(&psr->lock, flags);
del_timer_sync(&psr->flush_timer);
mutex_unlock(&psr->lock);
cancel_delayed_work_sync(&psr->flush_work);
return 0;
}
@ -162,9 +174,8 @@ EXPORT_SYMBOL(rockchip_drm_psr_deactivate);
static void rockchip_drm_do_flush(struct psr_drv *psr)
{
mod_timer(&psr->flush_timer,
round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT));
psr_set_state(psr, PSR_FLUSH);
mod_delayed_work(system_wq, &psr->flush_work, PSR_FLUSH_TIMEOUT_MS);
}
/**
@ -201,12 +212,11 @@ void rockchip_drm_psr_flush_all(struct drm_device *dev)
{
struct rockchip_drm_private *drm_drv = dev->dev_private;
struct psr_drv *psr;
unsigned long flags;
spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
mutex_lock(&drm_drv->psr_list_lock);
list_for_each_entry(psr, &drm_drv->psr_list, list)
rockchip_drm_do_flush(psr);
spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
mutex_unlock(&drm_drv->psr_list_lock);
}
EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
@ -223,7 +233,6 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder,
{
struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
struct psr_drv *psr;
unsigned long flags;
if (!encoder || !psr_set)
return -EINVAL;
@ -232,17 +241,17 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder,
if (!psr)
return -ENOMEM;
timer_setup(&psr->flush_timer, psr_flush_handler, 0);
spin_lock_init(&psr->lock);
INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
mutex_init(&psr->lock);
psr->active = true;
psr->state = PSR_DISABLE;
psr->encoder = encoder;
psr->set = psr_set;
spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
mutex_lock(&drm_drv->psr_list_lock);
list_add_tail(&psr->list, &drm_drv->psr_list);
spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
mutex_unlock(&drm_drv->psr_list_lock);
return 0;
}
@ -260,16 +269,15 @@ void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
{
struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
struct psr_drv *psr, *n;
unsigned long flags;
spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
mutex_lock(&drm_drv->psr_list_lock);
list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
if (psr->encoder == encoder) {
del_timer(&psr->flush_timer);
cancel_delayed_work_sync(&psr->flush_work);
list_del(&psr->list);
kfree(psr);
}
}
spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
mutex_unlock(&drm_drv->psr_list_lock);
}
EXPORT_SYMBOL(rockchip_drm_psr_unregister);

View File

@ -18,8 +18,8 @@
void rockchip_drm_psr_flush_all(struct drm_device *dev);
int rockchip_drm_psr_flush(struct drm_crtc *crtc);
int rockchip_drm_psr_activate(struct drm_crtc *crtc);
int rockchip_drm_psr_deactivate(struct drm_crtc *crtc);
int rockchip_drm_psr_activate(struct drm_encoder *encoder);
int rockchip_drm_psr_deactivate(struct drm_encoder *encoder);
int rockchip_drm_psr_register(struct drm_encoder *encoder,
void (*psr_set)(struct drm_encoder *, bool enable));

View File

@ -256,6 +256,9 @@ static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
{
uint16_t val = 1 << SCL_FT_DEFAULT_FIXPOINT_SHIFT;
if (vskiplines)
*vskiplines = 0;
if (is_horizontal) {
if (mode == SCALE_UP)
val = GET_SCL_FT_BIC(src, dst);
@ -296,7 +299,7 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win,
uint16_t vsu_mode;
uint16_t lb_mode;
uint32_t val;
int vskiplines = 0;
int vskiplines;
if (dst_w > 3840) {
DRM_DEV_ERROR(vop->dev, "Maximum dst width (3840) exceeded\n");
@ -566,8 +569,6 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
WARN_ON(vop->event);
rockchip_drm_psr_deactivate(&vop->crtc);
drm_crtc_vblank_off(crtc);
/*
@ -627,7 +628,6 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
struct vop_win *vop_win = to_vop_win(plane);
const struct vop_win_data *win = vop_win->data;
int ret;
struct drm_rect clip = {};
int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
DRM_PLANE_HELPER_NO_SCALING;
int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
@ -640,11 +640,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
if (WARN_ON(!crtc_state))
return -EINVAL;
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
min_scale, max_scale,
true, true);
if (ret)
@ -939,8 +935,6 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
VOP_REG_SET(vop, common, standby, 0);
rockchip_drm_psr_activate(&vop->crtc);
}
static bool vop_fs_irq_is_pending(struct vop *vop)

View File

@ -35,7 +35,6 @@ static int stm_gem_cma_dumb_create(struct drm_file *file,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
#ifdef CONFIG_MMU
unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
/*
@ -44,7 +43,6 @@ static int stm_gem_cma_dumb_create(struct drm_file *file,
*/
args->pitch = roundup(min_pitch, 128);
args->height = roundup(args->height, 4);
#endif
return drm_gem_cma_dumb_create_internal(file, dev, args);
}

View File

@ -1,6 +1,6 @@
config DRM_SUN4I
tristate "DRM Support for Allwinner A10 Display Engine"
depends on DRM && ARM && COMMON_CLK
depends on DRM && (ARM || ARM64) && COMMON_CLK
depends on ARCH_SUNXI || COMPILE_TEST
select DRM_GEM_CMA_HELPER
select DRM_KMS_HELPER

View File

@ -12,6 +12,7 @@ sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o
sun8i-drm-hdmi-y += sun8i_dw_hdmi.o
sun8i-drm-hdmi-y += sun8i_hdmi_phy.o
sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
sun8i_vi_layer.o sun8i_ui_scaler.o \

View File

@ -92,13 +92,8 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
}
static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
u32 format, u32 *mode)
static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)
{
if (plane && (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;
@ -191,8 +186,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(plane, fb->format->format,
&val);
ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val);
if (ret) {
DRM_DEBUG_DRIVER("Invalid format\n");
return ret;
@ -211,7 +205,7 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
u32 val;
int ret;
ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
ret = sun4i_backend_drm_format_to_layer(fmt, &val);
if (ret) {
DRM_DEBUG_DRIVER("Invalid format\n");
return ret;
@ -275,12 +269,16 @@ int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer,
struct drm_plane *plane)
{
struct drm_plane_state *state = plane->state;
struct sun4i_layer_state *p_state = state_to_sun4i_layer_state(state);
unsigned int priority = state->normalized_zpos;
unsigned int pipe = p_state->pipe;
DRM_DEBUG_DRIVER("Setting layer %d's priority to %d\n", layer, priority);
DRM_DEBUG_DRIVER("Setting layer %d's priority to %d and pipe %d\n",
layer, priority, pipe);
regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK |
SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK,
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(p_state->pipe) |
SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(priority));
return 0;
@ -325,12 +323,15 @@ static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
struct drm_crtc_state *crtc_state)
{
struct drm_plane_state *plane_states[SUN4I_BACKEND_NUM_LAYERS] = { 0 };
struct drm_atomic_state *state = crtc_state->state;
struct drm_device *drm = state->dev;
struct drm_plane *plane;
unsigned int num_planes = 0;
unsigned int num_alpha_planes = 0;
unsigned int num_frontend_planes = 0;
unsigned int current_pipe = 0;
unsigned int i;
DRM_DEBUG_DRIVER("Starting checking our planes\n");
@ -361,9 +362,19 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
if (fb->format->has_alpha)
num_alpha_planes++;
DRM_DEBUG_DRIVER("Plane zpos is %d\n",
plane_state->normalized_zpos);
/* Sort our planes by Zpos */
plane_states[plane_state->normalized_zpos] = plane_state;
num_planes++;
}
/* All our planes were disabled, bail out */
if (!num_planes)
return 0;
/*
* The hardware is a bit unusual here.
*
@ -400,6 +411,25 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
return -EINVAL;
}
/* We can't have an alpha plane at the lowest position */
if (plane_states[0]->fb->format->has_alpha)
return -EINVAL;
for (i = 1; i < num_planes; i++) {
struct drm_plane_state *p_state = plane_states[i];
struct drm_framebuffer *fb = p_state->fb;
struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(p_state);
/*
* The only alpha position is the lowest plane of the
* second pipe.
*/
if (fb->format->has_alpha)
current_pipe++;
s_state->pipe = current_pipe;
}
if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
return -EINVAL;

View File

@ -359,6 +359,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
{ .compatible = "allwinner,sun7i-a20-display-engine" },
{ .compatible = "allwinner,sun8i-a33-display-engine" },
{ .compatible = "allwinner,sun8i-a83t-display-engine" },
{ .compatible = "allwinner,sun8i-h3-display-engine" },
{ .compatible = "allwinner,sun8i-v3s-display-engine" },
{ }
};

View File

@ -19,13 +19,6 @@
#include "sun4i_layer.h"
#include "sunxi_engine.h"
struct sun4i_plane_desc {
enum drm_plane_type type;
u8 pipe;
const uint32_t *formats;
uint32_t nformats;
};
static void sun4i_backend_layer_reset(struct drm_plane *plane)
{
struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
@ -133,14 +126,7 @@ 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_primary[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_RGB888,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
};
static const uint32_t sun4i_backend_layer_formats_overlay[] = {
static const uint32_t sun4i_backend_layer_formats[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ARGB4444,
DRM_FORMAT_ARGB1555,
@ -151,24 +137,9 @@ static const uint32_t sun4i_backend_layer_formats_overlay[] = {
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,
struct sun4i_backend *backend,
const struct sun4i_plane_desc *plane)
enum drm_plane_type type)
{
struct sun4i_layer *layer;
int ret;
@ -180,8 +151,9 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
/* possible crtcs are set later */
ret = drm_universal_plane_init(drm, &layer->plane, 0,
&sun4i_backend_layer_funcs,
plane->formats, plane->nformats,
NULL, plane->type, NULL);
sun4i_backend_layer_formats,
ARRAY_SIZE(sun4i_backend_layer_formats),
NULL, type, NULL);
if (ret) {
dev_err(drm->dev, "Couldn't initialize layer\n");
return ERR_PTR(ret);
@ -191,6 +163,9 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
&sun4i_backend_layer_helper_funcs);
layer->backend = backend;
drm_plane_create_zpos_property(&layer->plane, 0, 0,
SUN4I_BACKEND_NUM_LAYERS - 1);
return layer;
}
@ -207,25 +182,17 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
if (!planes)
return ERR_PTR(-ENOMEM);
for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
for (i = 0; i < SUN4I_BACKEND_NUM_LAYERS; i++) {
enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
struct sun4i_layer *layer;
layer = sun4i_layer_init_one(drm, backend, plane);
layer = sun4i_layer_init_one(drm, backend, type);
if (IS_ERR(layer)) {
dev_err(drm->dev, "Couldn't initialize %s plane\n",
i ? "overlay" : "primary");
return ERR_CAST(layer);
};
drm_plane_create_zpos_immutable_property(&layer->plane, i);
DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
i ? "overlay" : "primary", plane->pipe);
regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
layer->id = i;
planes[i] = &layer->plane;
};

View File

@ -24,6 +24,7 @@ struct sun4i_layer {
struct sun4i_layer_state {
struct drm_plane_state state;
unsigned int pipe;
bool uses_frontend;
};

View File

@ -12,11 +12,158 @@
#include <linux/regmap.h>
#include <linux/reset.h>
#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0)
#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8)
#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8)
#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9)
#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16)
#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16)
#define SUN8I_HDMI_PHY_REXT_CTRL_REG 0x0004
#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31)
#define SUN8I_HDMI_PHY_READ_EN_REG 0x0010
#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545
#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG 0x0014
#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC 0x42494E47
#define SUN8I_HDMI_PHY_ANA_CFG1_REG 0x0020
#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SWI BIT(31)
#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWEND BIT(30)
#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWENC BIT(29)
#define SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW BIT(28)
#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVRCAL(x) ((x) << 26)
#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(x) ((x) << 24)
#define SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT BIT(23)
#define SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT BIT(22)
#define SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT BIT(21)
#define SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT BIT(20)
#define SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL BIT(19)
#define SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG BIT(18)
#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS BIT(17)
#define SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN BIT(16)
#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK GENMASK(15, 12)
#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL (0xf << 12)
#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK BIT(11)
#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 BIT(10)
#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 BIT(9)
#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 BIT(8)
#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK BIT(7)
#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 BIT(6)
#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 BIT(5)
#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 BIT(4)
#define SUN8I_HDMI_PHY_ANA_CFG1_CKEN BIT(3)
#define SUN8I_HDMI_PHY_ANA_CFG1_LDOEN BIT(2)
#define SUN8I_HDMI_PHY_ANA_CFG1_ENVBS BIT(1)
#define SUN8I_HDMI_PHY_ANA_CFG1_ENBI BIT(0)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG 0x0024
#define SUN8I_HDMI_PHY_ANA_CFG2_M_EN BIT(31)
#define SUN8I_HDMI_PHY_ANA_CFG2_PLLDBEN BIT(30)
#define SUN8I_HDMI_PHY_ANA_CFG2_SEN BIT(29)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDPD BIT(28)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDEN BIT(27)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLRCK BIT(26)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLR(x) ((x) << 23)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK BIT(22)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN BIT(21)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CD(x) ((x) << 19)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(x) ((x) << 17)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK BIT(16)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW BIT(15)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(x) ((x) << 13)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(x) ((x) << 10)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOSTCK(x) ((x) << 8)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOST(x) ((x) << 6)
#define SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(x) ((x) << 0)
#define SUN8I_HDMI_PHY_ANA_CFG3_REG 0x0028
#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOWCK(x) ((x) << 30)
#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOW(x) ((x) << 28)
#define SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(x) ((x) << 18)
#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(x) ((x) << 14)
#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMPCK(x) ((x) << 11)
#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(x) ((x) << 7)
#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(x) ((x) << 4)
#define SUN8I_HDMI_PHY_ANA_CFG3_SDAPD BIT(3)
#define SUN8I_HDMI_PHY_ANA_CFG3_SDAEN BIT(2)
#define SUN8I_HDMI_PHY_ANA_CFG3_SCLPD BIT(1)
#define SUN8I_HDMI_PHY_ANA_CFG3_SCLEN BIT(0)
#define SUN8I_HDMI_PHY_PLL_CFG1_REG 0x002c
#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 BIT(31)
#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD BIT(30)
#define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN BIT(29)
#define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28)
#define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27)
#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL BIT(26)
#define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25)
#define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22)
#define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20)
#define SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN BIT(19)
#define SUN8I_HDMI_PHY_PLL_CFG1_CS BIT(18)
#define SUN8I_HDMI_PHY_PLL_CFG1_CP_S(x) ((x) << 13)
#define SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(x) ((x) << 7)
#define SUN8I_HDMI_PHY_PLL_CFG1_BWS BIT(6)
#define SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK GENMASK(5, 0)
#define SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT 0
#define SUN8I_HDMI_PHY_PLL_CFG2_REG 0x0030
#define SUN8I_HDMI_PHY_PLL_CFG2_SV_H BIT(31)
#define SUN8I_HDMI_PHY_PLL_CFG2_PDCLKSEL(x) ((x) << 29)
#define SUN8I_HDMI_PHY_PLL_CFG2_CLKSTEP(x) ((x) << 27)
#define SUN8I_HDMI_PHY_PLL_CFG2_PSET(x) ((x) << 24)
#define SUN8I_HDMI_PHY_PLL_CFG2_PCLK_SEL BIT(23)
#define SUN8I_HDMI_PHY_PLL_CFG2_AUTOSYNC_DIS BIT(22)
#define SUN8I_HDMI_PHY_PLL_CFG2_VREG2_OUT_EN BIT(21)
#define SUN8I_HDMI_PHY_PLL_CFG2_VREG1_OUT_EN BIT(20)
#define SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN BIT(19)
#define SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN(x) ((x) << 16)
#define SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(x) ((x) << 12)
#define SUN8I_HDMI_PHY_PLL_CFG2_VCO_RST_IN BIT(11)
#define SUN8I_HDMI_PHY_PLL_CFG2_SINT_FRAC BIT(10)
#define SUN8I_HDMI_PHY_PLL_CFG2_SDIV2 BIT(9)
#define SUN8I_HDMI_PHY_PLL_CFG2_S(x) ((x) << 6)
#define SUN8I_HDMI_PHY_PLL_CFG2_S6P25_7P5 BIT(5)
#define SUN8I_HDMI_PHY_PLL_CFG2_S5_7 BIT(4)
#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK GENMASK(3, 0)
#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_SHIFT 0
#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV(x) (((x) - 1) << 0)
#define SUN8I_HDMI_PHY_PLL_CFG3_REG 0x0034
#define SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2 BIT(0)
#define SUN8I_HDMI_PHY_ANA_STS_REG 0x0038
#define SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT 11
#define SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK GENMASK(16, 11)
#define SUN8I_HDMI_PHY_ANA_STS_RCALEND2D BIT(7)
#define SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK GENMASK(5, 0)
#define SUN8I_HDMI_PHY_CEC_REG 0x003c
struct sun8i_hdmi_phy;
struct sun8i_hdmi_phy_variant {
bool has_phy_clk;
void (*phy_init)(struct sun8i_hdmi_phy *phy);
void (*phy_disable)(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy);
int (*phy_config)(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy,
unsigned int clk_rate);
};
struct sun8i_hdmi_phy {
struct clk *clk_bus;
struct clk *clk_mod;
struct regmap *regs;
struct reset_control *rst_phy;
struct clk *clk_bus;
struct clk *clk_mod;
struct clk *clk_phy;
struct clk *clk_pll0;
unsigned int rcal;
struct regmap *regs;
struct reset_control *rst_phy;
struct sun8i_hdmi_phy_variant *variant;
};
struct sun8i_dw_hdmi {
@ -41,4 +188,6 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
#endif /* _SUN8I_DW_HDMI_H_ */

View File

@ -3,47 +3,21 @@
* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
*/
#include <linux/delay.h>
#include <linux/of_address.h>
#include "sun8i_dw_hdmi.h"
#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0)
#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8)
#define SUN8I_HDMI_PHY_DBG_CTRL_POL(val) (val << 8)
#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16)
#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16)
#define SUN8I_HDMI_PHY_REXT_CTRL_REG 0x0004
#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31)
#define SUN8I_HDMI_PHY_READ_EN_REG 0x0010
#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545
#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG 0x0014
#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC 0x42494E47
/*
* Address can be actually any value. Here is set to same value as
* it is set in BSP driver.
*/
#define I2C_ADDR 0x69
static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
struct drm_display_mode *mode)
static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy,
unsigned int clk_rate)
{
struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
u32 val = 0;
if ((mode->flags & DRM_MODE_FLAG_NHSYNC) &&
(mode->flags & DRM_MODE_FLAG_NHSYNC)) {
val = 0x03;
}
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK,
SUN8I_HDMI_PHY_DBG_CTRL_POL(val));
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
@ -63,21 +37,21 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
* release any documentation, explanation of this values can
* be found in i.MX 6Dual/6Quad Reference Manual.
*/
if (mode->crtc_clock <= 27000) {
if (clk_rate <= 27000000) {
dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
} else if (mode->crtc_clock <= 74250) {
} else if (clk_rate <= 74250000) {
dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
} else if (mode->crtc_clock <= 148500) {
} else if (clk_rate <= 148500000) {
dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
@ -100,12 +74,173 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
return 0;
};
}
static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy,
unsigned int clk_rate)
{
u32 pll_cfg1_init;
u32 pll_cfg2_init;
u32 ana_cfg1_end;
u32 ana_cfg2_init;
u32 ana_cfg3_init;
u32 b_offset = 0;
u32 val;
/* bandwidth / frequency independent settings */
pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN |
SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN |
SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) |
SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) |
SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN |
SUN8I_HDMI_PHY_PLL_CFG1_CS |
SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) |
SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) |
SUN8I_HDMI_PHY_PLL_CFG1_BWS;
pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H |
SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN |
SUN8I_HDMI_PHY_PLL_CFG2_SDIV2;
ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) |
SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT |
SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT |
SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT |
SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT |
SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL |
SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG |
SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS |
SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN |
SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK |
SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 |
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
SUN8I_HDMI_PHY_ANA_CFG1_CKEN |
SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
SUN8I_HDMI_PHY_ANA_CFG1_ENBI;
ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN |
SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK |
SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN |
SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) |
SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1);
ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) |
SUN8I_HDMI_PHY_ANA_CFG3_SDAEN |
SUN8I_HDMI_PHY_ANA_CFG3_SCLEN;
/* bandwidth / frequency dependent settings */
if (clk_rate <= 27000000) {
pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
SUN8I_HDMI_PHY_PLL_CFG2_S(4);
ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) |
SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5);
} else if (clk_rate <= 74250000) {
pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
SUN8I_HDMI_PHY_PLL_CFG2_S(5);
ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) |
SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7);
} else if (clk_rate <= 148500000) {
pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
SUN8I_HDMI_PHY_PLL_CFG2_S(6);
ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2);
ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) |
SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9);
} else {
b_offset = 2;
pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63);
pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) |
SUN8I_HDMI_PHY_PLL_CFG2_S(7);
ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4);
ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) |
SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13);
}
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
(u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
pll_cfg2_init);
usleep_range(10000, 15000);
regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG,
SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
SUN8I_HDMI_PHY_PLL_CFG1_PLLEN,
SUN8I_HDMI_PHY_PLL_CFG1_PLLEN);
msleep(100);
/* get B value */
regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >>
SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT;
val = min(val + b_offset, (u32)0x3f);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
SUN8I_HDMI_PHY_PLL_CFG1_REG_OD,
SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
SUN8I_HDMI_PHY_PLL_CFG1_REG_OD);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK,
val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT);
msleep(100);
regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end);
regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init);
regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init);
return 0;
}
static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
struct drm_display_mode *mode)
{
struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
u32 val = 0;
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC;
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);
if (phy->variant->has_phy_clk)
clk_set_rate(phy->clk_phy, mode->crtc_clock * 1000);
return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000);
};
static void sun8i_hdmi_phy_disable_a83t(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy)
{
dw_hdmi_phy_gen2_txpwron(hdmi, 0);
dw_hdmi_phy_gen2_pddq(hdmi, 1);
@ -113,6 +248,23 @@ static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
}
static void sun8i_hdmi_phy_disable_h3(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy)
{
regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
}
static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
{
struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
phy->variant->phy_disable(hdmi, phy);
}
static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
.init = &sun8i_hdmi_phy_config,
.disable = &sun8i_hdmi_phy_disable,
@ -121,16 +273,8 @@ static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
.setup_hpd = &dw_hdmi_phy_setup_hpd,
};
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
{
/* enable read access to HDMI controller */
regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
SUN8I_HDMI_PHY_READ_EN_MAGIC);
/* unscramble register offsets */
regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
@ -144,6 +288,91 @@ void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
}
static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
{
unsigned int val;
regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_ENBI,
SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
udelay(5);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN,
SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_ENVBS,
SUN8I_HDMI_PHY_ANA_CFG1_ENVBS);
usleep_range(10, 20);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_LDOEN,
SUN8I_HDMI_PHY_ANA_CFG1_LDOEN);
udelay(5);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_CKEN,
SUN8I_HDMI_PHY_ANA_CFG1_CKEN);
usleep_range(40, 100);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL,
SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL);
usleep_range(100, 200);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG,
SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2,
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2);
/* wait for calibration to finish */
regmap_read_poll_timeout(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, val,
(val & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D),
100, 2000);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK,
SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK,
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK);
/* enable DDC communication */
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG,
SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
SUN8I_HDMI_PHY_ANA_CFG3_SDAEN,
SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
/* set HW control of CEC pins */
regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0);
/* read calibration data */
regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2;
}
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
{
/* enable read access to HDMI controller */
regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
SUN8I_HDMI_PHY_READ_EN_MAGIC);
/* unscramble register offsets */
regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
phy->variant->phy_init(phy);
}
const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void)
{
return &sun8i_hdmi_phy_ops;
@ -153,24 +382,46 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
.max_register = SUN8I_HDMI_PHY_CEC_REG,
.name = "phy"
};
static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
.phy_init = &sun8i_hdmi_phy_init_a83t,
.phy_disable = &sun8i_hdmi_phy_disable_a83t,
.phy_config = &sun8i_hdmi_phy_config_a83t,
};
static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
.has_phy_clk = true,
.phy_init = &sun8i_hdmi_phy_init_h3,
.phy_disable = &sun8i_hdmi_phy_disable_h3,
.phy_config = &sun8i_hdmi_phy_config_h3,
};
static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
{ .compatible = "allwinner,sun8i-a83t-hdmi-phy" },
{
.compatible = "allwinner,sun8i-a83t-hdmi-phy",
.data = &sun8i_a83t_hdmi_phy,
},
{
.compatible = "allwinner,sun8i-h3-hdmi-phy",
.data = &sun8i_h3_hdmi_phy,
},
{ /* sentinel */ }
};
int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
{
const struct of_device_id *match;
struct device *dev = hdmi->dev;
struct sun8i_hdmi_phy *phy;
struct resource res;
void __iomem *regs;
int ret;
if (!of_match_node(sun8i_hdmi_phy_of_table, node)) {
match = of_match_node(sun8i_hdmi_phy_of_table, node);
if (!match) {
dev_err(dev, "Incompatible HDMI PHY\n");
return -EINVAL;
}
@ -179,6 +430,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
if (!phy)
return -ENOMEM;
phy->variant = (struct sun8i_hdmi_phy_variant *)match->data;
ret = of_address_to_resource(node, 0, &res);
if (ret) {
dev_err(dev, "phy: Couldn't get our resources\n");
@ -211,11 +464,26 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
goto err_put_clk_bus;
}
if (phy->variant->has_phy_clk) {
phy->clk_pll0 = of_clk_get_by_name(node, "pll-0");
if (IS_ERR(phy->clk_pll0)) {
dev_err(dev, "Could not get pll-0 clock\n");
ret = PTR_ERR(phy->clk_pll0);
goto err_put_clk_mod;
}
ret = sun8i_phy_clk_create(phy, dev);
if (ret) {
dev_err(dev, "Couldn't create the PHY clock\n");
goto err_put_clk_pll0;
}
}
phy->rst_phy = of_reset_control_get_shared(node, "phy");
if (IS_ERR(phy->rst_phy)) {
dev_err(dev, "Could not get phy reset control\n");
ret = PTR_ERR(phy->rst_phy);
goto err_put_clk_mod;
goto err_put_clk_pll0;
}
ret = reset_control_deassert(phy->rst_phy);
@ -246,6 +514,9 @@ err_deassert_rst_phy:
reset_control_assert(phy->rst_phy);
err_put_rst_phy:
reset_control_put(phy->rst_phy);
err_put_clk_pll0:
if (phy->variant->has_phy_clk)
clk_put(phy->clk_pll0);
err_put_clk_mod:
clk_put(phy->clk_mod);
err_put_clk_bus:
@ -265,6 +536,8 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi)
reset_control_put(phy->rst_phy);
if (phy->variant->has_phy_clk)
clk_put(phy->clk_pll0);
clk_put(phy->clk_mod);
clk_put(phy->clk_bus);
}

View File

@ -0,0 +1,132 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
*/
#include <linux/clk-provider.h>
#include "sun8i_dw_hdmi.h"
struct sun8i_phy_clk {
struct clk_hw hw;
struct sun8i_hdmi_phy *phy;
};
static inline struct sun8i_phy_clk *hw_to_phy_clk(struct clk_hw *hw)
{
return container_of(hw, struct sun8i_phy_clk, hw);
}
static int sun8i_phy_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
unsigned long rate = req->rate;
unsigned long best_rate = 0;
struct clk_hw *parent;
int best_div = 1;
int i;
parent = clk_hw_get_parent(hw);
for (i = 1; i <= 16; i++) {
unsigned long ideal = rate * i;
unsigned long rounded;
rounded = clk_hw_round_rate(parent, ideal);
if (rounded == ideal) {
best_rate = rounded;
best_div = i;
break;
}
if (!best_rate ||
abs(rate - rounded / i) <
abs(rate - best_rate / best_div)) {
best_rate = rounded;
best_div = i;
}
}
req->rate = best_rate / best_div;
req->best_parent_rate = best_rate;
req->best_parent_hw = parent;
return 0;
}
static unsigned long sun8i_phy_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct sun8i_phy_clk *priv = hw_to_phy_clk(hw);
u32 reg;
regmap_read(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, &reg);
reg = ((reg >> SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_SHIFT) &
SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK) + 1;
return parent_rate / reg;
}
static int sun8i_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct sun8i_phy_clk *priv = hw_to_phy_clk(hw);
unsigned long best_rate = 0;
u8 best_m = 0, m;
for (m = 1; m <= 16; m++) {
unsigned long tmp_rate = parent_rate / m;
if (tmp_rate > rate)
continue;
if (!best_rate ||
(rate - tmp_rate) < (rate - best_rate)) {
best_rate = tmp_rate;
best_m = m;
}
}
regmap_update_bits(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
SUN8I_HDMI_PHY_PLL_CFG2_PREDIV(best_m));
return 0;
}
static const struct clk_ops sun8i_phy_clk_ops = {
.determine_rate = sun8i_phy_clk_determine_rate,
.recalc_rate = sun8i_phy_clk_recalc_rate,
.set_rate = sun8i_phy_clk_set_rate,
};
int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev)
{
struct clk_init_data init;
struct sun8i_phy_clk *priv;
const char *parents[1];
parents[0] = __clk_get_name(phy->clk_pll0);
if (!parents[0])
return -ENODEV;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
init.name = "hdmi-phy-clk";
init.ops = &sun8i_phy_clk_ops;
init.parent_names = parents;
init.num_parents = 1;
init.flags = CLK_SET_RATE_PARENT;
priv->phy = phy;
priv->hw.init = &init;
phy->clk_phy = devm_clk_register(dev, &priv->hw);
if (IS_ERR(phy->clk_phy))
return PTR_ERR(phy->clk_phy);
return 0;
}

View File

@ -492,6 +492,14 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
.ccsc = 0,
.mod_rate = 432000000,
.scaler_mask = 0xf,
.ui_num = 3,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.vi_num = 2,
.ui_num = 1,
@ -509,6 +517,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
.compatible = "allwinner,sun8i-a83t-de2-mixer-1",
.data = &sun8i_a83t_mixer1_cfg,
},
{
.compatible = "allwinner,sun8i-h3-de2-mixer-0",
.data = &sun8i_h3_mixer0_cfg,
},
{
.compatible = "allwinner,sun8i-v3s-de2-mixer",
.data = &sun8i_v3s_mixer_cfg,

View File

@ -211,7 +211,6 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state;
int min_scale, max_scale;
struct drm_rect clip = {};
if (!crtc)
return 0;
@ -220,10 +219,6 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
if (WARN_ON(!crtc_state))
return -EINVAL;
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
min_scale = DRM_PLANE_HELPER_NO_SCALING;
max_scale = DRM_PLANE_HELPER_NO_SCALING;
@ -232,7 +227,7 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
max_scale = SUN8I_UI_SCALER_SCALE_MAX;
}
return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
return drm_atomic_helper_check_plane_state(state, crtc_state,
min_scale, max_scale,
true, true);
}

View File

@ -239,7 +239,6 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state;
int min_scale, max_scale;
struct drm_rect clip = {};
if (!crtc)
return 0;
@ -248,10 +247,6 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
if (WARN_ON(!crtc_state))
return -EINVAL;
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
min_scale = DRM_PLANE_HELPER_NO_SCALING;
max_scale = DRM_PLANE_HELPER_NO_SCALING;
@ -260,7 +255,7 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
max_scale = SUN8I_VI_SCALER_SCALE_MAX;
}
return drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
return drm_atomic_helper_check_plane_state(state, crtc_state,
min_scale, max_scale,
true, true);
}

View File

@ -82,7 +82,6 @@ int tegra_plane_state_add(struct tegra_plane *plane,
{
struct drm_crtc_state *crtc_state;
struct tegra_dc_state *tegra;
struct drm_rect clip = {};
int err;
/* Propagate errors from allocation or locking failures. */
@ -90,12 +89,8 @@ int tegra_plane_state_add(struct tegra_plane *plane,
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
/* Check plane state for visibility and calculate clipping bounds */
err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
err = drm_atomic_helper_check_plane_state(state, crtc_state,
0, INT_MAX, true, true);
if (err < 0)
return err;

View File

@ -23,6 +23,7 @@ config TINYDRM_ILI9225
config TINYDRM_MI0283QT
tristate "DRM support for MI0283QT"
depends on DRM_TINYDRM && SPI
depends on BACKLIGHT_CLASS_DEVICE
select TINYDRM_MIPI_DBI
help
DRM driver for the Multi-Inno MI0283QT display panel
@ -54,6 +55,7 @@ config TINYDRM_ST7586
config TINYDRM_ST7735R
tristate "DRM support for Sitronix ST7735R display panels"
depends on DRM_TINYDRM && SPI
depends on BACKLIGHT_CLASS_DEVICE
select TINYDRM_MIPI_DBI
help
DRM driver Sitronix ST7735R with one of the following LCDs:

View File

@ -273,16 +273,20 @@ static void tve200_display_update(struct drm_simple_display_pipe *pipe,
}
}
int tve200_enable_vblank(struct drm_device *drm, unsigned int crtc)
static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct tve200_drm_dev_private *priv = drm->dev_private;
writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN);
return 0;
}
void tve200_disable_vblank(struct drm_device *drm, unsigned int crtc)
static void tve200_display_disable_vblank(struct drm_simple_display_pipe *pipe)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct tve200_drm_dev_private *priv = drm->dev_private;
writel(0, priv->regs + TVE200_INT_EN);
@ -300,6 +304,8 @@ static const struct drm_simple_display_pipe_funcs tve200_display_funcs = {
.disable = tve200_display_disable,
.update = tve200_display_update,
.prepare_fb = tve200_display_prepare_fb,
.enable_vblank = tve200_display_enable_vblank,
.disable_vblank = tve200_display_disable_vblank,
};
int tve200_display_init(struct drm_device *drm)

View File

@ -113,8 +113,6 @@ struct tve200_drm_dev_private {
container_of(x, struct tve200_drm_connector, connector)
int tve200_display_init(struct drm_device *dev);
int tve200_enable_vblank(struct drm_device *drm, unsigned int crtc);
void tve200_disable_vblank(struct drm_device *drm, unsigned int crtc);
irqreturn_t tve200_irq(int irq, void *data);
int tve200_connector_init(struct drm_device *dev);
int tve200_encoder_init(struct drm_device *dev);

View File

@ -162,9 +162,6 @@ static struct drm_driver tve200_drm_driver = {
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.enable_vblank = tve200_enable_vblank,
.disable_vblank = tve200_disable_vblank,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_import = drm_gem_prime_import,

View File

@ -681,7 +681,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
HDMI_WRITE(VC4_HDMI_FIFO_CTL,
drift | VC4_HDMI_FIFO_CTL_RECENTER);
udelay(1000);
usleep_range(1000, 1100);
HDMI_WRITE(VC4_HDMI_FIFO_CTL,
drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
HDMI_WRITE(VC4_HDMI_FIFO_CTL,

View File

@ -215,6 +215,7 @@ int vc4_kms_load(struct drm_device *dev)
dev->mode_config.funcs = &vc4_mode_funcs;
dev->mode_config.preferred_depth = 24;
dev->mode_config.async_page_flip = true;
dev->mode_config.allow_fb_modifiers = true;
drm_mode_config_reset(dev);

View File

@ -906,6 +906,32 @@ out:
ctx);
}
static bool vc4_format_mod_supported(struct drm_plane *plane,
uint32_t format,
uint64_t modifier)
{
/* Support T_TILING for RGB formats only. */
switch (format) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_RGB565:
case DRM_FORMAT_BGR565:
case DRM_FORMAT_ARGB1555:
case DRM_FORMAT_XRGB1555:
return true;
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV16:
default:
return (modifier == DRM_FORMAT_MOD_LINEAR);
}
}
static const struct drm_plane_funcs vc4_plane_funcs = {
.update_plane = vc4_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
@ -914,6 +940,7 @@ static const struct drm_plane_funcs vc4_plane_funcs = {
.reset = vc4_plane_reset,
.atomic_duplicate_state = vc4_plane_duplicate_state,
.atomic_destroy_state = vc4_plane_destroy_state,
.format_mod_supported = vc4_format_mod_supported,
};
struct drm_plane *vc4_plane_init(struct drm_device *dev,
@ -925,6 +952,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
u32 num_formats = 0;
int ret = 0;
unsigned i;
static const uint64_t modifiers[] = {
DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
GFP_KERNEL);
@ -945,7 +977,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
ret = drm_universal_plane_init(dev, plane, 0,
&vc4_plane_funcs,
formats, num_formats,
NULL, type, NULL);
modifiers, type, NULL);
drm_plane_helper_add(plane, &vc4_plane_helper_funcs);

View File

@ -61,9 +61,9 @@ static void virtio_gpu_user_framebuffer_destroy(struct drm_framebuffer *fb)
static int
virtio_gpu_framebuffer_surface_dirty(struct drm_framebuffer *fb,
struct drm_file *file_priv,
unsigned flags, unsigned color,
unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
unsigned num_clips)
unsigned int num_clips)
{
struct virtio_gpu_framebuffer *virtio_gpu_fb
= to_virtio_gpu_framebuffer(fb);
@ -96,6 +96,7 @@ virtio_gpu_framebuffer_init(struct drm_device *dev,
{
int ret;
struct virtio_gpu_object *bo;
vgfb->obj = obj;
bo = gem_to_virtio_gpu_obj(obj);
@ -387,7 +388,7 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev)
for (i = 0 ; i < vgdev->num_scanouts; ++i)
vgdev_output_init(vgdev, i);
drm_mode_config_reset(vgdev->ddev);
drm_mode_config_reset(vgdev->ddev);
return 0;
}

View File

@ -54,6 +54,7 @@ static int virtio_gpu_probe(struct virtio_device *vdev)
static void virtio_gpu_remove(struct virtio_device *vdev)
{
struct drm_device *dev = vdev->priv;
drm_put_dev(dev);
}
@ -112,7 +113,6 @@ static const struct file_operations virtio_gpu_driver_fops = {
.llseek = noop_llseek,
};
static struct drm_driver driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC,
.load = virtio_gpu_driver_load,

View File

@ -246,7 +246,7 @@ int virtio_gpu_fbdev_init(struct virtio_gpu_device *vgdev);
void virtio_gpu_fbdev_fini(struct virtio_gpu_device *vgdev);
int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *qfb,
struct drm_clip_rect *clips,
unsigned num_clips);
unsigned int num_clips);
/* virtio vg */
int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev);
void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev);
@ -363,12 +363,12 @@ int virtgpu_gem_prime_pin(struct drm_gem_object *obj);
void virtgpu_gem_prime_unpin(struct drm_gem_object *obj);
struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj);
struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *sgt);
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *sgt);
void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj);
void virtgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
int virtgpu_gem_prime_mmap(struct drm_gem_object *obj,
struct vm_area_struct *vma);
struct vm_area_struct *vma);
static inline struct virtio_gpu_object*
virtio_gpu_object_ref(struct virtio_gpu_object *bo)

View File

@ -118,7 +118,7 @@ static int virtio_gpu_dirty_update(struct virtio_gpu_framebuffer *fb,
int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *vgfb,
struct drm_clip_rect *clips,
unsigned num_clips)
unsigned int num_clips)
{
struct virtio_gpu_device *vgdev = vgfb->base.dev->dev_private;
struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(vgfb->obj);
@ -127,6 +127,7 @@ int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *vgfb,
int left, right, top, bottom;
int i;
int inc = 1;
if (!num_clips) {
num_clips = 1;
clips = &norect;
@ -172,6 +173,7 @@ static void virtio_gpu_3d_fillrect(struct fb_info *info,
const struct fb_fillrect *rect)
{
struct virtio_gpu_fbdev *vfbdev = info->par;
drm_fb_helper_sys_fillrect(info, rect);
virtio_gpu_dirty_update(&vfbdev->vgfb, true, rect->dx, rect->dy,
rect->width, rect->height);
@ -182,6 +184,7 @@ static void virtio_gpu_3d_copyarea(struct fb_info *info,
const struct fb_copyarea *area)
{
struct virtio_gpu_fbdev *vfbdev = info->par;
drm_fb_helper_sys_copyarea(info, area);
virtio_gpu_dirty_update(&vfbdev->vgfb, true, area->dx, area->dy,
area->width, area->height);
@ -192,6 +195,7 @@ static void virtio_gpu_3d_imageblit(struct fb_info *info,
const struct fb_image *image)
{
struct virtio_gpu_fbdev *vfbdev = info->par;
drm_fb_helper_sys_imageblit(info, image);
virtio_gpu_dirty_update(&vfbdev->vgfb, true, image->dx, image->dy,
image->width, image->height);

View File

@ -124,6 +124,7 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv,
{
struct drm_gem_object *gobj;
struct virtio_gpu_object *obj;
BUG_ON(!offset_p);
gobj = drm_gem_object_lookup(file_priv, handle);
if (gobj == NULL)

View File

@ -83,6 +83,7 @@ static void virtio_gpu_unref_list(struct list_head *head)
struct ttm_validate_buffer *buf;
struct ttm_buffer_object *bo;
struct virtio_gpu_object *qobj;
list_for_each_entry(buf, head, head) {
bo = buf->bo;
qobj = container_of(bo, struct virtio_gpu_object, tbo);
@ -478,6 +479,7 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev,
int ret;
struct virtio_gpu_drv_cap_cache *cache_ent;
void *ptr;
if (vgdev->num_capsets == 0)
return -ENOSYS;
@ -532,33 +534,34 @@ copy_exit:
struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = {
DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VIRTGPU_EXECBUFFER, virtio_gpu_execbuffer_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VIRTGPU_GETPARAM, virtio_gpu_getparam_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE,
virtio_gpu_resource_create_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_INFO, virtio_gpu_resource_info_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
/* make transfer async to the main ring? - no sure, can we
thread these in the underlying GL */
* thread these in the underlying GL
*/
DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_FROM_HOST,
virtio_gpu_transfer_from_host_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_TO_HOST,
virtio_gpu_transfer_to_host_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VIRTGPU_WAIT, virtio_gpu_wait_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VIRTGPU_GET_CAPS, virtio_gpu_get_caps_ioctl,
DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
};

View File

@ -25,7 +25,8 @@
#include "virtgpu_drv.h"
/* Empty Implementations as there should not be any other driver for a virtual
* device that might share buffers with virtgpu */
* device that might share buffers with virtgpu
*/
int virtgpu_gem_prime_pin(struct drm_gem_object *obj)
{
@ -38,7 +39,6 @@ void virtgpu_gem_prime_unpin(struct drm_gem_object *obj)
WARN_ONCE(1, "not implemented");
}
struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");

View File

@ -177,7 +177,6 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
struct ttm_mem_reg *mem)
{
mem->mm_node = (void *)NULL;
return;
}
static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
@ -225,7 +224,7 @@ static int virtio_gpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_CACHED;
break;
default:
DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type);
return -EINVAL;
}
return 0;
@ -244,7 +243,6 @@ static void virtio_gpu_evict_flags(struct ttm_buffer_object *bo,
placement->busy_placement = &placements;
placement->num_placement = 1;
placement->num_busy_placement = 1;
return;
}
static int virtio_gpu_verify_access(struct ttm_buffer_object *bo,

View File

@ -62,6 +62,7 @@ void virtio_gpu_ctrl_ack(struct virtqueue *vq)
{
struct drm_device *dev = vq->vdev->priv;
struct virtio_gpu_device *vgdev = dev->dev_private;
schedule_work(&vgdev->ctrlq.dequeue_work);
}
@ -69,6 +70,7 @@ void virtio_gpu_cursor_ack(struct virtqueue *vq)
{
struct drm_device *dev = vq->vdev->priv;
struct virtio_gpu_device *vgdev = dev->dev_private;
schedule_work(&vgdev->cursorq.dequeue_work);
}
@ -272,7 +274,7 @@ static int virtio_gpu_queue_ctrl_buffer_locked(struct virtio_gpu_device *vgdev,
return -ENODEV;
sg_init_one(&vcmd, vbuf->buf, vbuf->size);
sgs[outcnt+incnt] = &vcmd;
sgs[outcnt + incnt] = &vcmd;
outcnt++;
if (vbuf->data_size) {
@ -381,7 +383,8 @@ retry:
}
/* just create gem objects for userspace and long lived objects,
just use dma_alloced pages for the queue objects? */
* just use dma_alloced pages for the queue objects?
*/
/* create a basic resource */
void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
@ -593,7 +596,6 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev,
wake_up(&vgdev->resp_wq);
}
int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev)
{
struct virtio_gpu_ctrl_hdr *cmd_p;
@ -707,8 +709,8 @@ void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_CTX_CREATE);
cmd_p->hdr.ctx_id = cpu_to_le32(id);
cmd_p->nlen = cpu_to_le32(nlen);
strncpy(cmd_p->debug_name, name, sizeof(cmd_p->debug_name)-1);
cmd_p->debug_name[sizeof(cmd_p->debug_name)-1] = 0;
strncpy(cmd_p->debug_name, name, sizeof(cmd_p->debug_name) - 1);
cmd_p->debug_name[sizeof(cmd_p->debug_name) - 1] = 0;
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
}
@ -852,6 +854,7 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
if (!obj->pages) {
int ret;
ret = virtio_gpu_object_get_sg_table(vgdev, obj);
if (ret)
return ret;

View File

@ -443,17 +443,12 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
{
struct drm_crtc_state *crtc_state = NULL;
struct drm_framebuffer *new_fb = state->fb;
struct drm_rect clip = {};
int ret;
if (state->crtc)
crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
if (crtc_state && crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
ret = drm_atomic_helper_check_plane_state(state, crtc_state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, true);

View File

@ -55,7 +55,6 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane,
struct drm_framebuffer *fb = plane_state->fb;
struct drm_crtc *crtc = plane_state->crtc;
struct drm_crtc_state *crtc_state;
struct drm_rect clip = {};
int min_scale = FRAC_16_16(1, 8);
int max_scale = FRAC_16_16(8, 1);
@ -75,12 +74,8 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane,
if (!plane_state->crtc)
return -EINVAL;
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
&clip, min_scale, max_scale,
min_scale, max_scale,
true, true);
}
@ -291,7 +286,6 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane,
struct drm_framebuffer *fb = plane_state->fb;
struct drm_crtc *crtc = plane_state->crtc;
struct drm_crtc_state *crtc_state;
struct drm_rect clip = {};
if (!crtc || !fb)
return 0;
@ -309,12 +303,7 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane,
if (!plane_state->crtc)
return -EINVAL;
if (crtc_state->enable)
drm_mode_get_hv_timing(&crtc_state->mode,
&clip.x2, &clip.y2);
return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
&clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, true);

View File

@ -13,6 +13,8 @@
#include <drm/drm_crtc.h>
struct analogix_dp_device;
enum analogix_dp_devtype {
EXYNOS_DP,
RK3288_DP,
@ -29,6 +31,7 @@ struct analogix_dp_plat_data {
struct drm_panel *panel;
struct drm_encoder *encoder;
struct drm_connector *connector;
bool skip_connector;
int (*power_on)(struct analogix_dp_plat_data *);
int (*power_off)(struct analogix_dp_plat_data *);
@ -38,16 +41,17 @@ struct analogix_dp_plat_data {
struct drm_connector *);
};
int analogix_dp_psr_supported(struct device *dev);
int analogix_dp_enable_psr(struct device *dev);
int analogix_dp_disable_psr(struct device *dev);
int analogix_dp_psr_supported(struct analogix_dp_device *dp);
int analogix_dp_enable_psr(struct analogix_dp_device *dp);
int analogix_dp_disable_psr(struct analogix_dp_device *dp);
int analogix_dp_resume(struct device *dev);
int analogix_dp_suspend(struct device *dev);
int analogix_dp_resume(struct analogix_dp_device *dp);
int analogix_dp_suspend(struct analogix_dp_device *dp);
int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
struct analogix_dp_plat_data *plat_data);
void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
struct analogix_dp_device *
analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
struct analogix_dp_plat_data *plat_data);
void analogix_dp_unbind(struct analogix_dp_device *dp);
int analogix_dp_start_crc(struct drm_connector *connector);
int analogix_dp_stop_crc(struct drm_connector *connector);

View File

@ -753,6 +753,28 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
(old_plane_state) = (__state)->planes[__i].old_state,\
(new_plane_state) = (__state)->planes[__i].new_state, 1))
/**
* for_each_oldnew_plane_in_state_reverse - iterate over all planes in an atomic
* update in reverse order
* @__state: &struct drm_atomic_state pointer
* @plane: &struct drm_plane iteration cursor
* @old_plane_state: &struct drm_plane_state iteration cursor for the old state
* @new_plane_state: &struct drm_plane_state iteration cursor for the new state
* @__i: int iteration cursor, for macro-internal use
*
* This iterates over all planes in an atomic update in reverse order,
* tracking both old and new state. This is useful in places where the
* state delta needs to be considered, for example in atomic check functions.
*/
#define for_each_oldnew_plane_in_state_reverse(__state, plane, old_plane_state, new_plane_state, __i) \
for ((__i) = ((__state)->dev->mode_config.num_total_plane - 1); \
(__i) >= 0; \
(__i)--) \
for_each_if ((__state)->planes[__i].ptr && \
((plane) = (__state)->planes[__i].ptr, \
(old_plane_state) = (__state)->planes[__i].old_state,\
(new_plane_state) = (__state)->planes[__i].new_state, 1))
/**
* for_each_old_plane_in_state - iterate over all planes in an atomic update
* @__state: &struct drm_atomic_state pointer

View File

@ -40,7 +40,6 @@ int drm_atomic_helper_check_modeset(struct drm_device *dev,
struct drm_atomic_state *state);
int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
const struct drm_crtc_state *crtc_state,
const struct drm_rect *clip,
int min_scale,
int max_scale,
bool can_position,

View File

@ -26,6 +26,7 @@
#include <linux/ctype.h>
struct drm_crtc;
struct drm_plane;
uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision);
@ -37,4 +38,22 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
int gamma_size);
enum drm_color_encoding {
DRM_COLOR_YCBCR_BT601,
DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_BT2020,
DRM_COLOR_ENCODING_MAX,
};
enum drm_color_range {
DRM_COLOR_YCBCR_LIMITED_RANGE,
DRM_COLOR_YCBCR_FULL_RANGE,
DRM_COLOR_RANGE_MAX,
};
int drm_plane_create_color_properties(struct drm_plane *plane,
u32 supported_encodings,
u32 supported_ranges,
enum drm_color_encoding default_encoding,
enum drm_color_range default_range);
#endif

View File

@ -26,6 +26,7 @@
#include <linux/list.h>
#include <linux/ctype.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_color_mgmt.h>
struct drm_crtc;
struct drm_printer;
@ -112,6 +113,20 @@ struct drm_plane_state {
unsigned int zpos;
unsigned int normalized_zpos;
/**
* @color_encoding:
*
* Color encoding for non RGB formats
*/
enum drm_color_encoding color_encoding;
/**
* @color_range:
*
* Color range for non RGB formats
*/
enum drm_color_range color_range;
/* Clipped coordinates */
struct drm_rect src, dst;
@ -558,6 +573,23 @@ struct drm_plane {
struct drm_property *zpos_property;
struct drm_property *rotation_property;
/**
* @color_encoding_property:
*
* Optional "COLOR_ENCODING" enum property for specifying
* color encoding for non RGB formats.
* See drm_plane_create_color_properties().
*/
struct drm_property *color_encoding_property;
/**
* @color_range_property:
*
* Optional "COLOR_RANGE" enum property for specifying
* color range for non RGB formats.
* See drm_plane_create_color_properties().
*/
struct drm_property *color_range_property;
};
#define obj_to_plane(x) container_of(x, struct drm_plane, base)

View File

@ -43,7 +43,6 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
struct drm_framebuffer *fb,
struct drm_rect *src,
struct drm_rect *dest,
const struct drm_rect *clip,
unsigned int rotation,
int min_scale,
int max_scale,

View File

@ -237,27 +237,29 @@ static inline bool drm_property_type_is(struct drm_property *property,
return property->flags & type;
}
struct drm_property *drm_property_create(struct drm_device *dev, int flags,
const char *name, int num_values);
struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
const char *name,
struct drm_property *drm_property_create(struct drm_device *dev,
u32 flags, const char *name,
int num_values);
struct drm_property *drm_property_create_enum(struct drm_device *dev,
u32 flags, const char *name,
const struct drm_prop_enum_list *props,
int num_values);
struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
int flags, const char *name,
u32 flags, const char *name,
const struct drm_prop_enum_list *props,
int num_props,
uint64_t supported_bits);
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
const char *name,
struct drm_property *drm_property_create_range(struct drm_device *dev,
u32 flags, const char *name,
uint64_t min, uint64_t max);
struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
int flags, const char *name,
u32 flags, const char *name,
int64_t min, int64_t max);
struct drm_property *drm_property_create_object(struct drm_device *dev,
int flags, const char *name, uint32_t type);
struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
const char *name);
u32 flags, const char *name,
uint32_t type);
struct drm_property *drm_property_create_bool(struct drm_device *dev,
u32 flags, const char *name);
int drm_property_add_enum(struct drm_property *property, int index,
uint64_t value, const char *name);
void drm_property_destroy(struct drm_device *dev, struct drm_property *property);

View File

@ -24,9 +24,30 @@ struct drm_simple_display_pipe_funcs {
/**
* @mode_valid:
*
* This function is called to filter out valid modes from the
* suggestions suggested by the bridge or display. This optional
* hook is passed in when initializing the pipeline.
* This callback is used to check if a specific mode is valid in the
* crtc used in this simple display pipe. This should be implemented
* if the display pipe has some sort of restriction in the modes
* it can display. For example, a given display pipe may be responsible
* to set a clock value. If the clock can not produce all the values
* for the available modes then this callback can be used to restrict
* the number of modes to only the ones that can be displayed. Another
* reason can be bandwidth mitigation: the memory port on the display
* controller can have bandwidth limitations not allowing pixel data
* to be fetched at any rate.
*
* This hook is used by the probe helpers to filter the mode list in
* drm_helper_probe_single_connector_modes(), and it is used by the
* atomic helpers to validate modes supplied by userspace in
* drm_atomic_helper_check_modeset().
*
* This function is optional.
*
* NOTE:
*
* Since this function is both called from the check phase of an atomic
* commit, and the mode validation in the probe paths it is not allowed
* to look at anything else but the passed-in mode, and validate it
* against configuration-invariant hardware constraints.
*
* RETURNS:
*
@ -107,6 +128,24 @@ struct drm_simple_display_pipe_funcs {
*/
void (*cleanup_fb)(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state);
/**
* @enable_vblank:
*
* Optional, called by &drm_crtc_funcs.enable_vblank. Please read
* the documentation for the &drm_crtc_funcs.enable_vblank hook for
* more details.
*/
int (*enable_vblank)(struct drm_simple_display_pipe *pipe);
/**
* @disable_vblank:
*
* Optional, called by &drm_crtc_funcs.disable_vblank. Please read
* the documentation for the &drm_crtc_funcs.disable_vblank hook for
* more details.
*/
void (*disable_vblank)(struct drm_simple_display_pipe *pipe);
};
/**

View File

@ -363,7 +363,7 @@ struct drm_mode_get_connector {
__u32 pad;
};
#define DRM_MODE_PROP_PENDING (1<<0)
#define DRM_MODE_PROP_PENDING (1<<0) /* deprecated, do not use */
#define DRM_MODE_PROP_RANGE (1<<1)
#define DRM_MODE_PROP_IMMUTABLE (1<<2)
#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */
@ -598,8 +598,11 @@ struct drm_mode_crtc_lut {
};
struct drm_color_ctm {
/* Conversion matrix in S31.32 format. */
__s64 matrix[9];
/*
* Conversion matrix in S31.32 sign-magnitude
* (not two's complement!) format.
*/
__u64 matrix[9];
};
struct drm_color_lut {