mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-16 09:34:22 +08:00
drm-misc-next for v5.6:
UAPI Changes: - Allow overriding number of bootup penguins in fbcon using fbcon=logo-count:n. Cross-subsystem Changes: - fbdev fixes for mmp, and make it work with CONFIG_COMPILE_TEST. - Use devm_platform_ioremap_resource in fbdev drivers. - Various small fbdev fixes. Core Changes: - Support scanline alignment for dumb buffers. - Add atomic_check() hook to bridge ops, to support bus format negotiation. - Add gem_create_object() to vram helpers. Driver Changes: - Rockchip: Add support for PX30. - Use generic fbdev code and dumb helpers in hisilicon/hibmc. - Add support for Leadtek LTK500HD1829 panel, and xinpeng XPP055C272. - Clock fixes for atmel-hlcdc. - Various smaller fixes to all drivers. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAl4UcF4ACgkQ/lWMcqZw E8PKXQ/8DDTNq4kN7fInb1Bo/X/K5nGPABDrT8RaZn794D0w7WqE8pVQ+sLkAx/Q m5kNpfulh6ws5eZ/4mhntsKRpMVObfjhUZ4/4XL6BiMW2OmTe0Vv5b/YDmQrW+3H cANXyrJNWR1mzvU6Z1eFeHMKXcmujyrqxpKGHmeaRxb9dsrlOqpIOzkvRPN1SzWv 4iiblr608uhTy0Df7+3pjjnveq6MWI38lZpezDu8+iEjfQYQH/pIdgC0IK6Ydowp dyZ2tmJwghag4YIqN62q7uCb1FjPHXrXqq46/U35k6zwrL6FxzP7Q6oLyJW0uEI7 OGfgssiqp4GlVmo6NmBd68orx3WrwloJzz7bIIrgSnfX5hpoDSyErV9bQuvHcsLj uh6drY+XJaX1zr/i1Jj83ChU81LUIKDsHimbksNcpEiyqgCNnPfmYd8w3YBXoRJW FA54vv0+IxwWMZS/Ylx66Exxt2kVL7PYuZA529GLBTrLC5PFuwuhEcugmh5LjAXB TRMCcDf2CTuFMqBipewP+XyonMdoZDHD+dTNfbCgByp1vfyXrzwVV8Py2CLa+JlN dAEasoI1ENSRu95lYm2Xkbrw0Avqaya2ru8z3wwSnh/bLGoaZkMx/qxamSHXplR5 hR8b86z88LzDy+H2eufCC/KgMopxDJ6x3h2dtuFlFlWQLTY2D6U= =L7fz -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2020-01-07' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for v5.6: UAPI Changes: - Allow overriding number of bootup penguins in fbcon using fbcon=logo-count:n. Cross-subsystem Changes: - fbdev fixes for mmp, and make it work with CONFIG_COMPILE_TEST. - Use devm_platform_ioremap_resource in fbdev drivers. - Various small fbdev fixes. Core Changes: - Support scanline alignment for dumb buffers. - Add atomic_check() hook to bridge ops, to support bus format negotiation. - Add gem_create_object() to vram helpers. Driver Changes: - Rockchip: Add support for PX30. - Use generic fbdev code and dumb helpers in hisilicon/hibmc. - Add support for Leadtek LTK500HD1829 panel, and xinpeng XPP055C272. - Clock fixes for atmel-hlcdc. - Various smaller fixes to all drivers. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/8eff1e3f-ef0a-2dd9-9a14-6273b1d6f963@linux.intel.com
This commit is contained in:
commit
a566696cf9
@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/leadtek,ltk500hd1829.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Leadtek LTK500HD1829 5.0in 720x1280 DSI panel
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: leadtek,ltk500hd1829
|
||||
reg: true
|
||||
backlight: true
|
||||
reset-gpios: true
|
||||
iovcc-supply:
|
||||
description: regulator that supplies the iovcc voltage
|
||||
vcc-supply:
|
||||
description: regulator that supplies the vcc voltage
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- backlight
|
||||
- iovcc-supply
|
||||
- vcc-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
dsi@ff450000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "leadtek,ltk500hd1829";
|
||||
reg = <0>;
|
||||
backlight = <&backlight>;
|
||||
iovcc-supply = <&vcc_1v8>;
|
||||
vcc-supply = <&vcc_2v8>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/xinpeng,xpp055c272.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xinpeng XPP055C272 5.5in 720x1280 DSI panel
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: xinpeng,xpp055c272
|
||||
reg: true
|
||||
backlight: true
|
||||
reset-gpios: true
|
||||
iovcc-supply:
|
||||
description: regulator that supplies the iovcc voltage
|
||||
vci-supply:
|
||||
description: regulator that supplies the vci voltage
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- backlight
|
||||
- iovcc-supply
|
||||
- vci-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
dsi@ff450000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "xinpeng,xpp055c272";
|
||||
reg = <0>;
|
||||
backlight = <&backlight>;
|
||||
iovcc-supply = <&vcc_1v8>;
|
||||
vci-supply = <&vcc3v3_lcd>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -4,6 +4,7 @@ Rockchip RK3288 LVDS interface
|
||||
Required properties:
|
||||
- compatible: matching the soc type, one of
|
||||
- "rockchip,rk3288-lvds";
|
||||
- "rockchip,px30-lvds";
|
||||
|
||||
- reg: physical base address of the controller and length
|
||||
of memory mapped region.
|
||||
@ -18,6 +19,9 @@ Required properties:
|
||||
- rockchip,grf: phandle to the general register files syscon
|
||||
- rockchip,output: "rgb", "lvds" or "duallvds", This describes the output interface
|
||||
|
||||
- phys: LVDS/DSI DPHY (px30 only)
|
||||
- phy-names: name of the PHY, must be "dphy" (px30 only)
|
||||
|
||||
Optional properties:
|
||||
- pinctrl-names: must contain a "lcdc" entry.
|
||||
- pinctrl-0: pin control group to be used for this controller.
|
||||
|
@ -513,6 +513,8 @@ patternProperties:
|
||||
description: Lantiq Semiconductor
|
||||
"^lattice,.*":
|
||||
description: Lattice Semiconductor
|
||||
"^leadtek,.*":
|
||||
description: Shenzhen Leadtek Technology Co., Ltd.
|
||||
"^leez,.*":
|
||||
description: Leez
|
||||
"^lego,.*":
|
||||
@ -1056,6 +1058,8 @@ patternProperties:
|
||||
description: Extreme Engineering Solutions (X-ES)
|
||||
"^xillybus,.*":
|
||||
description: Xillybus Ltd.
|
||||
"^xinpeng,.*":
|
||||
description: Shenzhen Xinpeng Technology Co., Ltd
|
||||
"^xlnx,.*":
|
||||
description: Xilinx
|
||||
"^xunlong,.*":
|
||||
|
@ -127,7 +127,7 @@ C. Boot options
|
||||
is typically located on the same video card. Thus, the consoles that
|
||||
are controlled by the VGA console will be garbled.
|
||||
|
||||
4. fbcon=rotate:<n>
|
||||
5. fbcon=rotate:<n>
|
||||
|
||||
This option changes the orientation angle of the console display. The
|
||||
value 'n' accepts the following:
|
||||
@ -152,21 +152,21 @@ C. Boot options
|
||||
Actually, the underlying fb driver is totally ignorant of console
|
||||
rotation.
|
||||
|
||||
5. fbcon=margin:<color>
|
||||
6. fbcon=margin:<color>
|
||||
|
||||
This option specifies the color of the margins. The margins are the
|
||||
leftover area at the right and the bottom of the screen that are not
|
||||
used by text. By default, this area will be black. The 'color' value
|
||||
is an integer number that depends on the framebuffer driver being used.
|
||||
|
||||
6. fbcon=nodefer
|
||||
7. fbcon=nodefer
|
||||
|
||||
If the kernel is compiled with deferred fbcon takeover support, normally
|
||||
the framebuffer contents, left in place by the firmware/bootloader, will
|
||||
be preserved until there actually is some text is output to the console.
|
||||
This option causes fbcon to bind immediately to the fbdev device.
|
||||
|
||||
7. fbcon=logo-pos:<location>
|
||||
8. fbcon=logo-pos:<location>
|
||||
|
||||
The only possible 'location' is 'center' (without quotes), and when
|
||||
given, the bootup logo is moved from the default top-left corner
|
||||
@ -174,6 +174,11 @@ C. Boot options
|
||||
displayed due to multiple CPUs, the collected line of logos is moved
|
||||
as a whole.
|
||||
|
||||
9. fbcon=logo-count:<n>
|
||||
|
||||
The value 'n' overrides the number of bootup logos. 0 disables the
|
||||
logo, and -1 gives the default which is the number of online CPUs.
|
||||
|
||||
C. Attaching, Detaching and Unloading
|
||||
|
||||
Before going on to how to attach, detach and unload the framebuffer console, an
|
||||
|
@ -1144,8 +1144,7 @@ static int ast_cursor_init(struct drm_device *dev)
|
||||
size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) {
|
||||
gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev,
|
||||
size, 0, false);
|
||||
gbo = drm_gem_vram_create(dev, size, 0);
|
||||
if (IS_ERR(gbo)) {
|
||||
ret = PTR_ERR(gbo);
|
||||
goto err_drm_gem_vram_put;
|
||||
|
@ -73,7 +73,11 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
|
||||
unsigned long prate;
|
||||
unsigned int mask = ATMEL_HLCDC_CLKDIV_MASK | ATMEL_HLCDC_CLKPOL;
|
||||
unsigned int cfg = 0;
|
||||
int div;
|
||||
int div, ret;
|
||||
|
||||
ret = clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
|
||||
vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
|
||||
@ -95,14 +99,14 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
|
||||
(adj->crtc_hdisplay - 1) |
|
||||
((adj->crtc_vdisplay - 1) << 16));
|
||||
|
||||
prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
|
||||
mode_rate = adj->crtc_clock * 1000;
|
||||
if (!crtc->dc->desc->fixed_clksrc) {
|
||||
prate *= 2;
|
||||
cfg |= ATMEL_HLCDC_CLKSEL;
|
||||
mask |= ATMEL_HLCDC_CLKSEL;
|
||||
}
|
||||
|
||||
prate = 2 * clk_get_rate(crtc->dc->hlcdc->sys_clk);
|
||||
mode_rate = adj->crtc_clock * 1000;
|
||||
|
||||
div = DIV_ROUND_UP(prate, mode_rate);
|
||||
if (div < 2) {
|
||||
div = 2;
|
||||
@ -117,8 +121,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
|
||||
int div_low = prate / mode_rate;
|
||||
|
||||
if (div_low >= 2 &&
|
||||
((prate / div_low - mode_rate) <
|
||||
10 * (mode_rate - prate / div)))
|
||||
(10 * (prate / div_low - mode_rate) <
|
||||
(mode_rate - prate / div)))
|
||||
/*
|
||||
* At least 10 times better when using a higher
|
||||
* frequency than requested, instead of a lower.
|
||||
@ -147,6 +151,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
|
||||
ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
|
||||
ATMEL_HLCDC_GUARDTIME_MASK | ATMEL_HLCDC_MODE_MASK,
|
||||
cfg);
|
||||
|
||||
clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
|
@ -721,18 +721,10 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
|
||||
dc->hlcdc = dev_get_drvdata(dev->dev->parent);
|
||||
dev->dev_private = dc;
|
||||
|
||||
if (dc->desc->fixed_clksrc) {
|
||||
ret = clk_prepare_enable(dc->hlcdc->sys_clk);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable sys_clk\n");
|
||||
goto err_destroy_wq;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(dc->hlcdc->periph_clk);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to enable periph_clk\n");
|
||||
goto err_sys_clk_disable;
|
||||
goto err_destroy_wq;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev->dev);
|
||||
@ -768,9 +760,6 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
|
||||
err_periph_clk_disable:
|
||||
pm_runtime_disable(dev->dev);
|
||||
clk_disable_unprepare(dc->hlcdc->periph_clk);
|
||||
err_sys_clk_disable:
|
||||
if (dc->desc->fixed_clksrc)
|
||||
clk_disable_unprepare(dc->hlcdc->sys_clk);
|
||||
|
||||
err_destroy_wq:
|
||||
destroy_workqueue(dc->wq);
|
||||
@ -795,8 +784,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
|
||||
|
||||
pm_runtime_disable(dev->dev);
|
||||
clk_disable_unprepare(dc->hlcdc->periph_clk);
|
||||
if (dc->desc->fixed_clksrc)
|
||||
clk_disable_unprepare(dc->hlcdc->sys_clk);
|
||||
destroy_workqueue(dc->wq);
|
||||
}
|
||||
|
||||
@ -910,8 +897,6 @@ static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
|
||||
regmap_read(regmap, ATMEL_HLCDC_IMR, &dc->suspend.imr);
|
||||
regmap_write(regmap, ATMEL_HLCDC_IDR, dc->suspend.imr);
|
||||
clk_disable_unprepare(dc->hlcdc->periph_clk);
|
||||
if (dc->desc->fixed_clksrc)
|
||||
clk_disable_unprepare(dc->hlcdc->sys_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -921,8 +906,6 @@ static int atmel_hlcdc_dc_drm_resume(struct device *dev)
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
struct atmel_hlcdc_dc *dc = drm_dev->dev_private;
|
||||
|
||||
if (dc->desc->fixed_clksrc)
|
||||
clk_prepare_enable(dc->hlcdc->sys_clk);
|
||||
clk_prepare_enable(dc->hlcdc->periph_clk);
|
||||
regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, dc->suspend.imr);
|
||||
|
||||
|
@ -1289,19 +1289,21 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
|
||||
return conn_state->crtc;
|
||||
}
|
||||
|
||||
static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state)
|
||||
static void
|
||||
analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
struct drm_atomic_state *old_state = old_bridge_state->base.state;
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
int ret;
|
||||
|
||||
crtc = analogix_dp_get_new_crtc(dp, state);
|
||||
crtc = analogix_dp_get_new_crtc(dp, old_state);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
|
||||
/* Don't touch the panel if we're coming back from PSR */
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active)
|
||||
return;
|
||||
@ -1366,20 +1368,22 @@ out_dp_clk_pre:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state)
|
||||
static void
|
||||
analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
struct drm_atomic_state *old_state = old_bridge_state->base.state;
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
int timeout_loop = 0;
|
||||
int ret;
|
||||
|
||||
crtc = analogix_dp_get_new_crtc(dp, state);
|
||||
crtc = analogix_dp_get_new_crtc(dp, old_state);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
|
||||
old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
|
||||
/* Not a full enable, just disable PSR and continue */
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active) {
|
||||
ret = analogix_dp_disable_psr(dp);
|
||||
@ -1440,18 +1444,20 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
|
||||
dp->dpms_mode = DRM_MODE_DPMS_OFF;
|
||||
}
|
||||
|
||||
static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state)
|
||||
static void
|
||||
analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
struct drm_atomic_state *old_state = old_bridge_state->base.state;
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state = NULL;
|
||||
|
||||
crtc = analogix_dp_get_new_crtc(dp, state);
|
||||
crtc = analogix_dp_get_new_crtc(dp, old_state);
|
||||
if (!crtc)
|
||||
goto out;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
|
||||
if (!new_crtc_state)
|
||||
goto out;
|
||||
|
||||
@ -1463,20 +1469,21 @@ out:
|
||||
analogix_dp_bridge_disable(bridge);
|
||||
}
|
||||
|
||||
static
|
||||
void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state)
|
||||
static void
|
||||
analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
struct drm_atomic_state *old_state = old_bridge_state->base.state;
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
int ret;
|
||||
|
||||
crtc = analogix_dp_get_new_crtc(dp, state);
|
||||
crtc = analogix_dp_get_new_crtc(dp, old_state);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
|
||||
if (!new_crtc_state || !new_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
|
@ -512,7 +512,7 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi,
|
||||
struct cdns_dsi_output *output = &dsi->output;
|
||||
unsigned int tmp;
|
||||
bool sync_pulse = false;
|
||||
int bpp, nlanes;
|
||||
int bpp;
|
||||
|
||||
memset(dsi_cfg, 0, sizeof(*dsi_cfg));
|
||||
|
||||
@ -520,7 +520,6 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi,
|
||||
sync_pulse = true;
|
||||
|
||||
bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format);
|
||||
nlanes = output->dev->lanes;
|
||||
|
||||
if (mode_valid_check)
|
||||
tmp = mode->htotal -
|
||||
@ -785,13 +784,12 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
|
||||
unsigned long tx_byte_period;
|
||||
struct cdns_dsi_cfg dsi_cfg;
|
||||
u32 tmp, reg_wakeup, div;
|
||||
int bpp, nlanes;
|
||||
int nlanes;
|
||||
|
||||
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
|
||||
return;
|
||||
|
||||
mode = &bridge->encoder->crtc->state->adjusted_mode;
|
||||
bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format);
|
||||
nlanes = output->dev->lanes;
|
||||
|
||||
WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false));
|
||||
|
@ -291,7 +291,7 @@ static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct snd_pcm_hardware dw_hdmi_hw = {
|
||||
static const struct snd_pcm_hardware dw_hdmi_hw = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP |
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_drv.h>
|
||||
@ -1017,6 +1018,44 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
|
||||
connector->funcs->atomic_print_state(p, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_atomic_add_encoder_bridges - add bridges attached to an encoder
|
||||
* @state: atomic state
|
||||
* @encoder: DRM encoder
|
||||
*
|
||||
* This function adds all bridges attached to @encoder. This is needed to add
|
||||
* bridge states to @state and make them available when
|
||||
* &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are
|
||||
* called
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
|
||||
* then the w/w mutex code has detected a deadlock and the entire atomic
|
||||
* sequence must be restarted. All other errors are fatal.
|
||||
*/
|
||||
int
|
||||
drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_bridge_state *bridge_state;
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
if (!encoder)
|
||||
return 0;
|
||||
|
||||
DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n",
|
||||
encoder->base.id, encoder->name, state);
|
||||
|
||||
drm_for_each_bridge_in_chain(encoder, bridge) {
|
||||
bridge_state = drm_atomic_get_bridge_state(state, bridge);
|
||||
if (IS_ERR(bridge_state))
|
||||
return PTR_ERR(bridge_state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);
|
||||
|
||||
/**
|
||||
* drm_atomic_add_affected_connectors - add connectors for CRTC
|
||||
* @state: atomic state
|
||||
|
@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state)
|
||||
funcs = encoder->helper_private;
|
||||
|
||||
bridge = drm_bridge_chain_get_first_bridge(encoder);
|
||||
ret = drm_bridge_chain_mode_fixup(bridge,
|
||||
&new_crtc_state->mode,
|
||||
&new_crtc_state->adjusted_mode);
|
||||
if (!ret) {
|
||||
DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
|
||||
return -EINVAL;
|
||||
ret = drm_atomic_bridge_chain_check(bridge,
|
||||
new_crtc_state,
|
||||
new_conn_state);
|
||||
if (ret) {
|
||||
DRM_DEBUG_ATOMIC("Bridge atomic check failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (funcs && funcs->atomic_check) {
|
||||
@ -730,6 +730,26 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all connectors again, and add all affected bridges to
|
||||
* the state.
|
||||
*/
|
||||
for_each_oldnew_connector_in_state(state, connector,
|
||||
old_connector_state,
|
||||
new_connector_state, i) {
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
encoder = old_connector_state->best_encoder;
|
||||
ret = drm_atomic_add_encoder_bridges(state, encoder);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
encoder = new_connector_state->best_encoder;
|
||||
ret = drm_atomic_add_encoder_bridges(state, encoder);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mode_valid(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
|
||||
@ -89,6 +90,74 @@ void drm_bridge_remove(struct drm_bridge *bridge)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_remove);
|
||||
|
||||
static struct drm_bridge_state *
|
||||
drm_atomic_default_bridge_duplicate_state(struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_bridge_state *new;
|
||||
|
||||
if (WARN_ON(!bridge->base.state))
|
||||
return NULL;
|
||||
|
||||
new = kzalloc(sizeof(*new), GFP_KERNEL);
|
||||
if (new)
|
||||
__drm_atomic_helper_bridge_duplicate_state(bridge, new);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static struct drm_private_state *
|
||||
drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj)
|
||||
{
|
||||
struct drm_bridge *bridge = drm_priv_to_bridge(obj);
|
||||
struct drm_bridge_state *state;
|
||||
|
||||
if (bridge->funcs->atomic_duplicate_state)
|
||||
state = bridge->funcs->atomic_duplicate_state(bridge);
|
||||
else
|
||||
state = drm_atomic_default_bridge_duplicate_state(bridge);
|
||||
|
||||
return state ? &state->base : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_atomic_default_bridge_destroy_state(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *state)
|
||||
{
|
||||
/* Just a simple kfree() for now */
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static void
|
||||
drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
|
||||
struct drm_private_state *s)
|
||||
{
|
||||
struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
|
||||
struct drm_bridge *bridge = drm_priv_to_bridge(obj);
|
||||
|
||||
if (bridge->funcs->atomic_destroy_state)
|
||||
bridge->funcs->atomic_destroy_state(bridge, state);
|
||||
else
|
||||
drm_atomic_default_bridge_destroy_state(bridge, state);
|
||||
}
|
||||
|
||||
static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
|
||||
.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
|
||||
.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
|
||||
};
|
||||
|
||||
static struct drm_bridge_state *
|
||||
drm_atomic_default_bridge_reset(struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_bridge_state *bridge_state;
|
||||
|
||||
bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL);
|
||||
if (!bridge_state)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
__drm_atomic_helper_bridge_reset(bridge, bridge_state);
|
||||
return bridge_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_bridge_attach - attach the bridge to an encoder's chain
|
||||
*
|
||||
@ -114,6 +183,7 @@ EXPORT_SYMBOL(drm_bridge_remove);
|
||||
int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
|
||||
struct drm_bridge *previous)
|
||||
{
|
||||
struct drm_bridge_state *state;
|
||||
int ret;
|
||||
|
||||
if (!encoder || !bridge)
|
||||
@ -135,15 +205,35 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
|
||||
|
||||
if (bridge->funcs->attach) {
|
||||
ret = bridge->funcs->attach(bridge);
|
||||
if (ret < 0) {
|
||||
list_del(&bridge->chain_node);
|
||||
bridge->dev = NULL;
|
||||
bridge->encoder = NULL;
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto err_reset_bridge;
|
||||
}
|
||||
|
||||
if (bridge->funcs->atomic_reset)
|
||||
state = bridge->funcs->atomic_reset(bridge);
|
||||
else
|
||||
state = drm_atomic_default_bridge_reset(bridge);
|
||||
|
||||
if (IS_ERR(state)) {
|
||||
ret = PTR_ERR(state);
|
||||
goto err_detach_bridge;
|
||||
}
|
||||
|
||||
drm_atomic_private_obj_init(bridge->dev, &bridge->base,
|
||||
&state->base,
|
||||
&drm_bridge_priv_state_funcs);
|
||||
|
||||
return 0;
|
||||
|
||||
err_detach_bridge:
|
||||
if (bridge->funcs->detach)
|
||||
bridge->funcs->detach(bridge);
|
||||
|
||||
err_reset_bridge:
|
||||
bridge->dev = NULL;
|
||||
bridge->encoder = NULL;
|
||||
list_del(&bridge->chain_node);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_attach);
|
||||
|
||||
@ -155,6 +245,8 @@ void drm_bridge_detach(struct drm_bridge *bridge)
|
||||
if (WARN_ON(!bridge->dev))
|
||||
return;
|
||||
|
||||
drm_atomic_private_obj_fini(&bridge->base);
|
||||
|
||||
if (bridge->funcs->detach)
|
||||
bridge->funcs->detach(bridge);
|
||||
|
||||
@ -409,10 +501,19 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
|
||||
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
||||
if (iter->funcs->atomic_disable)
|
||||
iter->funcs->atomic_disable(iter, old_state);
|
||||
else if (iter->funcs->disable)
|
||||
if (iter->funcs->atomic_disable) {
|
||||
struct drm_bridge_state *old_bridge_state;
|
||||
|
||||
old_bridge_state =
|
||||
drm_atomic_get_old_bridge_state(old_state,
|
||||
iter);
|
||||
if (WARN_ON(!old_bridge_state))
|
||||
return;
|
||||
|
||||
iter->funcs->atomic_disable(iter, old_bridge_state);
|
||||
} else if (iter->funcs->disable) {
|
||||
iter->funcs->disable(iter);
|
||||
}
|
||||
|
||||
if (iter == bridge)
|
||||
break;
|
||||
@ -443,10 +544,20 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
|
||||
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
|
||||
if (bridge->funcs->atomic_post_disable)
|
||||
bridge->funcs->atomic_post_disable(bridge, old_state);
|
||||
else if (bridge->funcs->post_disable)
|
||||
if (bridge->funcs->atomic_post_disable) {
|
||||
struct drm_bridge_state *old_bridge_state;
|
||||
|
||||
old_bridge_state =
|
||||
drm_atomic_get_old_bridge_state(old_state,
|
||||
bridge);
|
||||
if (WARN_ON(!old_bridge_state))
|
||||
return;
|
||||
|
||||
bridge->funcs->atomic_post_disable(bridge,
|
||||
old_bridge_state);
|
||||
} else if (bridge->funcs->post_disable) {
|
||||
bridge->funcs->post_disable(bridge);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
|
||||
@ -475,10 +586,19 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
|
||||
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
||||
if (iter->funcs->atomic_pre_enable)
|
||||
iter->funcs->atomic_pre_enable(iter, old_state);
|
||||
else if (iter->funcs->pre_enable)
|
||||
if (iter->funcs->atomic_pre_enable) {
|
||||
struct drm_bridge_state *old_bridge_state;
|
||||
|
||||
old_bridge_state =
|
||||
drm_atomic_get_old_bridge_state(old_state,
|
||||
iter);
|
||||
if (WARN_ON(!old_bridge_state))
|
||||
return;
|
||||
|
||||
iter->funcs->atomic_pre_enable(iter, old_bridge_state);
|
||||
} else if (iter->funcs->pre_enable) {
|
||||
iter->funcs->pre_enable(iter);
|
||||
}
|
||||
|
||||
if (iter == bridge)
|
||||
break;
|
||||
@ -508,14 +628,385 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
|
||||
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
|
||||
if (bridge->funcs->atomic_enable)
|
||||
bridge->funcs->atomic_enable(bridge, old_state);
|
||||
else if (bridge->funcs->enable)
|
||||
if (bridge->funcs->atomic_enable) {
|
||||
struct drm_bridge_state *old_bridge_state;
|
||||
|
||||
old_bridge_state =
|
||||
drm_atomic_get_old_bridge_state(old_state,
|
||||
bridge);
|
||||
if (WARN_ON(!old_bridge_state))
|
||||
return;
|
||||
|
||||
bridge->funcs->atomic_enable(bridge, old_bridge_state);
|
||||
} else if (bridge->funcs->enable) {
|
||||
bridge->funcs->enable(bridge);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
|
||||
|
||||
static int drm_atomic_bridge_check(struct drm_bridge *bridge,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
if (bridge->funcs->atomic_check) {
|
||||
struct drm_bridge_state *bridge_state;
|
||||
int ret;
|
||||
|
||||
bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
|
||||
bridge);
|
||||
if (WARN_ON(!bridge_state))
|
||||
return -EINVAL;
|
||||
|
||||
ret = bridge->funcs->atomic_check(bridge, bridge_state,
|
||||
crtc_state, conn_state);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (bridge->funcs->mode_fixup) {
|
||||
if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode,
|
||||
&crtc_state->adjusted_mode))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to
|
||||
* the input end of a bridge
|
||||
* @bridge: bridge control structure
|
||||
* @bridge_state: new bridge state
|
||||
* @crtc_state: new CRTC state
|
||||
* @conn_state: new connector state
|
||||
* @output_fmt: tested output bus format
|
||||
* @num_input_fmts: will contain the size of the returned array
|
||||
*
|
||||
* This helper is a pluggable implementation of the
|
||||
* &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't
|
||||
* modify the bus configuration between their input and their output. It
|
||||
* returns an array of input formats with a single element set to @output_fmt.
|
||||
*
|
||||
* RETURNS:
|
||||
* a valid format array of size @num_input_fmts, or NULL if the allocation
|
||||
* failed
|
||||
*/
|
||||
u32 *
|
||||
drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *bridge_state,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state,
|
||||
u32 output_fmt,
|
||||
unsigned int *num_input_fmts)
|
||||
{
|
||||
u32 *input_fmts;
|
||||
|
||||
input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);
|
||||
if (!input_fmts) {
|
||||
*num_input_fmts = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*num_input_fmts = 1;
|
||||
input_fmts[0] = output_fmt;
|
||||
return input_fmts;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
|
||||
|
||||
static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
|
||||
struct drm_bridge *cur_bridge,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state,
|
||||
u32 out_bus_fmt)
|
||||
{
|
||||
struct drm_bridge_state *cur_state;
|
||||
unsigned int num_in_bus_fmts, i;
|
||||
struct drm_bridge *prev_bridge;
|
||||
u32 *in_bus_fmts;
|
||||
int ret;
|
||||
|
||||
prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
|
||||
cur_state = drm_atomic_get_new_bridge_state(crtc_state->state,
|
||||
cur_bridge);
|
||||
if (WARN_ON(!cur_state))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If bus format negotiation is not supported by this bridge, let's
|
||||
* pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and
|
||||
* hope that it can handle this situation gracefully (by providing
|
||||
* appropriate default values).
|
||||
*/
|
||||
if (!cur_bridge->funcs->atomic_get_input_bus_fmts) {
|
||||
if (cur_bridge != first_bridge) {
|
||||
ret = select_bus_fmt_recursive(first_bridge,
|
||||
prev_bridge, crtc_state,
|
||||
conn_state,
|
||||
MEDIA_BUS_FMT_FIXED);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED;
|
||||
cur_state->output_bus_cfg.format = out_bus_fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge,
|
||||
cur_state,
|
||||
crtc_state,
|
||||
conn_state,
|
||||
out_bus_fmt,
|
||||
&num_in_bus_fmts);
|
||||
if (!num_in_bus_fmts)
|
||||
return -ENOTSUPP;
|
||||
else if (!in_bus_fmts)
|
||||
return -ENOMEM;
|
||||
|
||||
if (first_bridge == cur_bridge) {
|
||||
cur_state->input_bus_cfg.format = in_bus_fmts[0];
|
||||
cur_state->output_bus_cfg.format = out_bus_fmt;
|
||||
kfree(in_bus_fmts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_in_bus_fmts; i++) {
|
||||
ret = select_bus_fmt_recursive(first_bridge, prev_bridge,
|
||||
crtc_state, conn_state,
|
||||
in_bus_fmts[i]);
|
||||
if (ret != -ENOTSUPP)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
cur_state->input_bus_cfg.format = in_bus_fmts[i];
|
||||
cur_state->output_bus_cfg.format = out_bus_fmt;
|
||||
}
|
||||
|
||||
kfree(in_bus_fmts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by &drm_atomic_bridge_chain_check() just before
|
||||
* calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
|
||||
* It performs bus format negotiation between bridge elements. The negotiation
|
||||
* happens in reverse order, starting from the last element in the chain up to
|
||||
* @bridge.
|
||||
*
|
||||
* Negotiation starts by retrieving supported output bus formats on the last
|
||||
* bridge element and testing them one by one. The test is recursive, meaning
|
||||
* that for each tested output format, the whole chain will be walked backward,
|
||||
* and each element will have to choose an input bus format that can be
|
||||
* transcoded to the requested output format. When a bridge element does not
|
||||
* support transcoding into a specific output format -ENOTSUPP is returned and
|
||||
* the next bridge element will have to try a different format. If none of the
|
||||
* combinations worked, -ENOTSUPP is returned and the atomic modeset will fail.
|
||||
*
|
||||
* This implementation is relying on
|
||||
* &drm_bridge_funcs.atomic_get_output_bus_fmts() and
|
||||
* &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported
|
||||
* input/output formats.
|
||||
*
|
||||
* When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by
|
||||
* the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts()
|
||||
* tries a single format: &drm_connector.display_info.bus_formats[0] if
|
||||
* available, MEDIA_BUS_FMT_FIXED otherwise.
|
||||
*
|
||||
* When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented,
|
||||
* &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the
|
||||
* bridge element that lacks this hook and asks the previous element in the
|
||||
* chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what
|
||||
* to do in that case (fail if they want to enforce bus format negotiation, or
|
||||
* provide a reasonable default if they need to support pipelines where not
|
||||
* all elements support bus format negotiation).
|
||||
*/
|
||||
static int
|
||||
drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_connector *conn = conn_state->connector;
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_bridge_state *last_bridge_state;
|
||||
unsigned int i, num_out_bus_fmts;
|
||||
struct drm_bridge *last_bridge;
|
||||
u32 *out_bus_fmts;
|
||||
int ret = 0;
|
||||
|
||||
last_bridge = list_last_entry(&encoder->bridge_chain,
|
||||
struct drm_bridge, chain_node);
|
||||
last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
|
||||
last_bridge);
|
||||
if (WARN_ON(!last_bridge_state))
|
||||
return -EINVAL;
|
||||
|
||||
if (last_bridge->funcs->atomic_get_output_bus_fmts) {
|
||||
const struct drm_bridge_funcs *funcs = last_bridge->funcs;
|
||||
|
||||
out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge,
|
||||
last_bridge_state,
|
||||
crtc_state,
|
||||
conn_state,
|
||||
&num_out_bus_fmts);
|
||||
if (!num_out_bus_fmts)
|
||||
return -ENOTSUPP;
|
||||
else if (!out_bus_fmts)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
num_out_bus_fmts = 1;
|
||||
out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL);
|
||||
if (!out_bus_fmts)
|
||||
return -ENOMEM;
|
||||
|
||||
if (conn->display_info.num_bus_formats &&
|
||||
conn->display_info.bus_formats)
|
||||
out_bus_fmts[0] = conn->display_info.bus_formats[0];
|
||||
else
|
||||
out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_out_bus_fmts; i++) {
|
||||
ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state,
|
||||
conn_state, out_bus_fmts[i]);
|
||||
if (ret != -ENOTSUPP)
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(out_bus_fmts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge,
|
||||
struct drm_connector *conn,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_bridge_state *bridge_state, *next_bridge_state;
|
||||
struct drm_bridge *next_bridge;
|
||||
u32 output_flags;
|
||||
|
||||
bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
|
||||
next_bridge = drm_bridge_get_next_bridge(bridge);
|
||||
|
||||
/*
|
||||
* Let's try to apply the most common case here, that is, propagate
|
||||
* display_info flags for the last bridge, and propagate the input
|
||||
* flags of the next bridge element to the output end of the current
|
||||
* bridge when the bridge is not the last one.
|
||||
* There are exceptions to this rule, like when signal inversion is
|
||||
* happening at the board level, but that's something drivers can deal
|
||||
* with from their &drm_bridge_funcs.atomic_check() implementation by
|
||||
* simply overriding the flags value we've set here.
|
||||
*/
|
||||
if (!next_bridge) {
|
||||
output_flags = conn->display_info.bus_flags;
|
||||
} else {
|
||||
next_bridge_state = drm_atomic_get_new_bridge_state(state,
|
||||
next_bridge);
|
||||
output_flags = next_bridge_state->input_bus_cfg.flags;
|
||||
}
|
||||
|
||||
bridge_state->output_bus_cfg.flags = output_flags;
|
||||
|
||||
/*
|
||||
* Propage the output flags to the input end of the bridge. Again, it's
|
||||
* not necessarily what all bridges want, but that's what most of them
|
||||
* do, and by doing that by default we avoid forcing drivers to
|
||||
* duplicate the "dummy propagation" logic.
|
||||
*/
|
||||
bridge_state->input_bus_cfg.flags = output_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain
|
||||
* @bridge: bridge control structure
|
||||
* @crtc_state: new CRTC state
|
||||
* @conn_state: new connector state
|
||||
*
|
||||
* First trigger a bus format negotiation before calling
|
||||
* &drm_bridge_funcs.atomic_check() (falls back on
|
||||
* &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain,
|
||||
* starting from the last bridge to the first. These are called before calling
|
||||
* &drm_encoder_helper_funcs.atomic_check()
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, a negative error code on failure
|
||||
*/
|
||||
int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_connector *conn = conn_state->connector;
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_bridge *iter;
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state,
|
||||
conn_state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Bus flags are propagated by default. If a bridge needs to
|
||||
* tweak the input bus flags for any reason, it should happen
|
||||
* in its &drm_bridge_funcs.atomic_check() implementation such
|
||||
* that preceding bridges in the chain can propagate the new
|
||||
* bus flags.
|
||||
*/
|
||||
drm_atomic_bridge_propagate_bus_flags(iter, conn,
|
||||
crtc_state->state);
|
||||
|
||||
ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (iter == bridge)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_bridge_chain_check);
|
||||
|
||||
/**
|
||||
* __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its
|
||||
* default
|
||||
* @bridge: the bridge this state is refers to
|
||||
* @state: bridge state to initialize
|
||||
*
|
||||
* Initialize the bridge state to default values. This is meant to be* called
|
||||
* by the bridge &drm_plane_funcs.reset hook for bridges that subclass the
|
||||
* bridge state.
|
||||
*/
|
||||
void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *state)
|
||||
{
|
||||
memset(state, 0, sizeof(*state));
|
||||
state->bridge = bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
|
||||
|
||||
/**
|
||||
* __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state
|
||||
* @bridge: bridge object
|
||||
* @state: atomic bridge state
|
||||
*
|
||||
* Copies atomic state from a bridge's current state and resets inferred values.
|
||||
* This is useful for drivers that subclass the bridge state.
|
||||
*/
|
||||
void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *state)
|
||||
{
|
||||
__drm_atomic_helper_private_obj_duplicate_state(&bridge->base,
|
||||
&state->base);
|
||||
state->bridge = bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* of_drm_find_bridge - find the bridge corresponding to the device node in
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_ttm_helper.h>
|
||||
@ -92,14 +93,18 @@ static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo,
|
||||
}
|
||||
|
||||
static int drm_gem_vram_init(struct drm_device *dev,
|
||||
struct ttm_bo_device *bdev,
|
||||
struct drm_gem_vram_object *gbo,
|
||||
size_t size, unsigned long pg_align,
|
||||
bool interruptible)
|
||||
size_t size, unsigned long pg_align)
|
||||
{
|
||||
struct drm_vram_mm *vmm = dev->vram_mm;
|
||||
struct ttm_bo_device *bdev;
|
||||
int ret;
|
||||
size_t acc_size;
|
||||
|
||||
if (WARN_ONCE(!vmm, "VRAM MM not initialized"))
|
||||
return -EINVAL;
|
||||
bdev = &vmm->bdev;
|
||||
|
||||
gbo->bo.base.funcs = &drm_gem_vram_object_funcs;
|
||||
|
||||
ret = drm_gem_object_init(dev, &gbo->bo.base, size);
|
||||
@ -112,7 +117,7 @@ static int drm_gem_vram_init(struct drm_device *dev,
|
||||
drm_gem_vram_placement(gbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
|
||||
|
||||
ret = ttm_bo_init(bdev, &gbo->bo, size, ttm_bo_type_device,
|
||||
&gbo->placement, pg_align, interruptible, acc_size,
|
||||
&gbo->placement, pg_align, false, acc_size,
|
||||
NULL, NULL, ttm_buffer_object_destroy);
|
||||
if (ret)
|
||||
goto err_drm_gem_object_release;
|
||||
@ -127,29 +132,33 @@ err_drm_gem_object_release:
|
||||
/**
|
||||
* drm_gem_vram_create() - Creates a VRAM-backed GEM object
|
||||
* @dev: the DRM device
|
||||
* @bdev: the TTM BO device backing the object
|
||||
* @size: the buffer size in bytes
|
||||
* @pg_align: the buffer's alignment in multiples of the page size
|
||||
* @interruptible: sleep interruptible if waiting for memory
|
||||
*
|
||||
* Returns:
|
||||
* A new instance of &struct drm_gem_vram_object on success, or
|
||||
* an ERR_PTR()-encoded error code otherwise.
|
||||
*/
|
||||
struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev,
|
||||
struct ttm_bo_device *bdev,
|
||||
size_t size,
|
||||
unsigned long pg_align,
|
||||
bool interruptible)
|
||||
unsigned long pg_align)
|
||||
{
|
||||
struct drm_gem_vram_object *gbo;
|
||||
int ret;
|
||||
|
||||
gbo = kzalloc(sizeof(*gbo), GFP_KERNEL);
|
||||
if (!gbo)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (dev->driver->gem_create_object) {
|
||||
struct drm_gem_object *gem =
|
||||
dev->driver->gem_create_object(dev, size);
|
||||
if (!gem)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
gbo = drm_gem_vram_of_gem(gem);
|
||||
} else {
|
||||
gbo = kzalloc(sizeof(*gbo), GFP_KERNEL);
|
||||
if (!gbo)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ret = drm_gem_vram_init(dev, bdev, gbo, size, pg_align, interruptible);
|
||||
ret = drm_gem_vram_init(dev, gbo, size, pg_align);
|
||||
if (ret < 0)
|
||||
goto err_kfree;
|
||||
|
||||
@ -483,9 +492,8 @@ EXPORT_SYMBOL(drm_gem_vram_vunmap);
|
||||
Helper for implementing &struct drm_driver.dumb_create
|
||||
* @file: the DRM file
|
||||
* @dev: the DRM device
|
||||
* @bdev: the TTM BO device managing the buffer object
|
||||
* @pg_align: the buffer's alignment in multiples of the page size
|
||||
* @interruptible: sleep interruptible if waiting for memory
|
||||
* @pitch_align: the scanline's alignment in powers of 2
|
||||
* @args: the arguments as provided to \
|
||||
&struct drm_driver.dumb_create
|
||||
*
|
||||
@ -500,9 +508,8 @@ EXPORT_SYMBOL(drm_gem_vram_vunmap);
|
||||
*/
|
||||
int drm_gem_vram_fill_create_dumb(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
struct ttm_bo_device *bdev,
|
||||
unsigned long pg_align,
|
||||
bool interruptible,
|
||||
unsigned long pitch_align,
|
||||
struct drm_mode_create_dumb *args)
|
||||
{
|
||||
size_t pitch, size;
|
||||
@ -510,14 +517,19 @@ int drm_gem_vram_fill_create_dumb(struct drm_file *file,
|
||||
int ret;
|
||||
u32 handle;
|
||||
|
||||
pitch = args->width * ((args->bpp + 7) / 8);
|
||||
pitch = args->width * DIV_ROUND_UP(args->bpp, 8);
|
||||
if (pitch_align) {
|
||||
if (WARN_ON_ONCE(!is_power_of_2(pitch_align)))
|
||||
return -EINVAL;
|
||||
pitch = ALIGN(pitch, pitch_align);
|
||||
}
|
||||
size = pitch * args->height;
|
||||
|
||||
size = roundup(size, PAGE_SIZE);
|
||||
if (!size)
|
||||
return -EINVAL;
|
||||
|
||||
gbo = drm_gem_vram_create(dev, bdev, size, pg_align, interruptible);
|
||||
gbo = drm_gem_vram_create(dev, size, pg_align);
|
||||
if (IS_ERR(gbo))
|
||||
return PTR_ERR(gbo);
|
||||
|
||||
@ -612,8 +624,7 @@ int drm_gem_vram_driver_dumb_create(struct drm_file *file,
|
||||
if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized"))
|
||||
return -EINVAL;
|
||||
|
||||
return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev, 0,
|
||||
false, args);
|
||||
return drm_gem_vram_fill_create_dumb(file, dev, 0, 0, args);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create);
|
||||
|
||||
|
@ -367,9 +367,9 @@ static void mipi_dbi_blank(struct mipi_dbi_dev *dbidev)
|
||||
memset(dbidev->tx_buf, 0, len);
|
||||
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0,
|
||||
(width >> 8) & 0xFF, (width - 1) & 0xFF);
|
||||
((width - 1) >> 8) & 0xFF, (width - 1) & 0xFF);
|
||||
mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0,
|
||||
(height >> 8) & 0xFF, (height - 1) & 0xFF);
|
||||
((height - 1) >> 8) & 0xFF, (height - 1) & 0xFF);
|
||||
mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START,
|
||||
(u8 *)dbidev->tx_buf, len);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o
|
||||
hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_ttm.o
|
||||
|
||||
obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
|
||||
|
@ -99,14 +99,12 @@ static void hibmc_plane_atomic_update(struct drm_plane *plane,
|
||||
s64 gpu_addr = 0;
|
||||
unsigned int line_l;
|
||||
struct hibmc_drm_private *priv = plane->dev->dev_private;
|
||||
struct hibmc_framebuffer *hibmc_fb;
|
||||
struct drm_gem_vram_object *gbo;
|
||||
|
||||
if (!state->fb)
|
||||
return;
|
||||
|
||||
hibmc_fb = to_hibmc_framebuffer(state->fb);
|
||||
gbo = drm_gem_vram_of_gem(hibmc_fb->obj);
|
||||
gbo = drm_gem_vram_of_gem(state->fb->obj[0]);
|
||||
|
||||
gpu_addr = drm_gem_vram_offset(gbo);
|
||||
if (WARN_ON_ONCE(gpu_addr < 0))
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_gem_vram_helper.h>
|
||||
#include <drm/drm_irq.h>
|
||||
#include <drm/drm_print.h>
|
||||
@ -54,6 +55,7 @@ static struct drm_driver hibmc_driver = {
|
||||
.desc = "hibmc drm driver",
|
||||
.major = 1,
|
||||
.minor = 0,
|
||||
.debugfs_init = drm_vram_mm_debugfs_init,
|
||||
.dumb_create = hibmc_dumb_create,
|
||||
.dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset,
|
||||
.gem_prime_mmap = drm_gem_prime_mmap,
|
||||
@ -247,8 +249,6 @@ static int hibmc_unload(struct drm_device *dev)
|
||||
{
|
||||
struct hibmc_drm_private *priv = dev->dev_private;
|
||||
|
||||
hibmc_fbdev_fini(priv);
|
||||
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
|
||||
if (dev->irq_enabled)
|
||||
@ -307,7 +307,7 @@ static int hibmc_load(struct drm_device *dev)
|
||||
/* reset all the states of crtc/plane/encoder/connector */
|
||||
drm_mode_config_reset(dev);
|
||||
|
||||
ret = hibmc_fbdev_init(priv);
|
||||
ret = drm_fbdev_generic_setup(dev, 16);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize fbdev: %d\n", ret);
|
||||
goto err;
|
||||
|
@ -18,18 +18,6 @@
|
||||
#include <drm/drm_framebuffer.h>
|
||||
|
||||
struct drm_device;
|
||||
struct drm_gem_object;
|
||||
|
||||
struct hibmc_framebuffer {
|
||||
struct drm_framebuffer fb;
|
||||
struct drm_gem_object *obj;
|
||||
};
|
||||
|
||||
struct hibmc_fbdev {
|
||||
struct drm_fb_helper helper; /* must be first */
|
||||
struct hibmc_framebuffer *fb;
|
||||
int size;
|
||||
};
|
||||
|
||||
struct hibmc_drm_private {
|
||||
/* hw */
|
||||
@ -42,13 +30,8 @@ struct hibmc_drm_private {
|
||||
/* drm */
|
||||
struct drm_device *dev;
|
||||
bool mode_config_initialized;
|
||||
|
||||
/* fbdev */
|
||||
struct hibmc_fbdev *fbdev;
|
||||
};
|
||||
|
||||
#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb)
|
||||
|
||||
void hibmc_set_power_mode(struct hibmc_drm_private *priv,
|
||||
unsigned int power_mode);
|
||||
void hibmc_set_current_gate(struct hibmc_drm_private *priv,
|
||||
@ -56,15 +39,6 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv,
|
||||
|
||||
int hibmc_de_init(struct hibmc_drm_private *priv);
|
||||
int hibmc_vdac_init(struct hibmc_drm_private *priv);
|
||||
int hibmc_fbdev_init(struct hibmc_drm_private *priv);
|
||||
void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
|
||||
|
||||
int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
|
||||
struct drm_gem_object **obj);
|
||||
struct hibmc_framebuffer *
|
||||
hibmc_framebuffer_init(struct drm_device *dev,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj);
|
||||
|
||||
int hibmc_mm_init(struct hibmc_drm_private *hibmc);
|
||||
void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
|
||||
|
@ -1,240 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Hisilicon Hibmc SoC drm driver
|
||||
*
|
||||
* Based on the bochs drm driver.
|
||||
*
|
||||
* Copyright (c) 2016 Huawei Limited.
|
||||
*
|
||||
* Author:
|
||||
* Rongrong Zou <zourongrong@huawei.com>
|
||||
* Rongrong Zou <zourongrong@gmail.com>
|
||||
* Jianhua Li <lijianhua@huawei.com>
|
||||
*/
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_vram_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include "hibmc_drm_drv.h"
|
||||
|
||||
static int hibmcfb_create_object(
|
||||
struct hibmc_drm_private *priv,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object **gobj_p)
|
||||
{
|
||||
struct drm_gem_object *gobj;
|
||||
struct drm_device *dev = priv->dev;
|
||||
u32 size;
|
||||
int ret = 0;
|
||||
|
||||
size = mode_cmd->pitches[0] * mode_cmd->height;
|
||||
ret = hibmc_gem_create(dev, size, true, &gobj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*gobj_p = gobj;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct fb_ops hibmc_drm_fb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_check_var = drm_fb_helper_check_var,
|
||||
.fb_set_par = drm_fb_helper_set_par,
|
||||
.fb_fillrect = drm_fb_helper_sys_fillrect,
|
||||
.fb_copyarea = drm_fb_helper_sys_copyarea,
|
||||
.fb_imageblit = drm_fb_helper_sys_imageblit,
|
||||
.fb_pan_display = drm_fb_helper_pan_display,
|
||||
.fb_blank = drm_fb_helper_blank,
|
||||
.fb_setcmap = drm_fb_helper_setcmap,
|
||||
};
|
||||
|
||||
static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct hibmc_fbdev *hi_fbdev =
|
||||
container_of(helper, struct hibmc_fbdev, helper);
|
||||
struct hibmc_drm_private *priv = helper->dev->dev_private;
|
||||
struct fb_info *info;
|
||||
struct drm_mode_fb_cmd2 mode_cmd;
|
||||
struct drm_gem_object *gobj = NULL;
|
||||
int ret = 0;
|
||||
size_t size;
|
||||
unsigned int bytes_per_pixel;
|
||||
struct drm_gem_vram_object *gbo = NULL;
|
||||
void *base;
|
||||
|
||||
DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
|
||||
sizes->surface_width, sizes->surface_height,
|
||||
sizes->surface_bpp);
|
||||
|
||||
bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
|
||||
|
||||
mode_cmd.width = sizes->surface_width;
|
||||
mode_cmd.height = sizes->surface_height;
|
||||
mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
|
||||
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
|
||||
sizes->surface_depth);
|
||||
|
||||
size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height);
|
||||
|
||||
ret = hibmcfb_create_object(priv, &mode_cmd, &gobj);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create fbcon backing object: %d\n", ret);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
gbo = drm_gem_vram_of_gem(gobj);
|
||||
|
||||
ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin fbcon: %d\n", ret);
|
||||
goto out_unref_gem;
|
||||
}
|
||||
|
||||
base = drm_gem_vram_kmap(gbo, true, NULL);
|
||||
if (IS_ERR(base)) {
|
||||
ret = PTR_ERR(base);
|
||||
DRM_ERROR("failed to kmap fbcon: %d\n", ret);
|
||||
goto out_unpin_bo;
|
||||
}
|
||||
|
||||
info = drm_fb_helper_alloc_fbi(helper);
|
||||
if (IS_ERR(info)) {
|
||||
ret = PTR_ERR(info);
|
||||
DRM_ERROR("failed to allocate fbi: %d\n", ret);
|
||||
goto out_release_fbi;
|
||||
}
|
||||
|
||||
hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
|
||||
if (IS_ERR(hi_fbdev->fb)) {
|
||||
ret = PTR_ERR(hi_fbdev->fb);
|
||||
hi_fbdev->fb = NULL;
|
||||
DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
|
||||
goto out_release_fbi;
|
||||
}
|
||||
|
||||
priv->fbdev->size = size;
|
||||
hi_fbdev->helper.fb = &hi_fbdev->fb->fb;
|
||||
|
||||
info->fbops = &hibmc_drm_fb_ops;
|
||||
|
||||
drm_fb_helper_fill_info(info, &priv->fbdev->helper, sizes);
|
||||
|
||||
info->screen_base = base;
|
||||
info->screen_size = size;
|
||||
|
||||
info->fix.smem_start = gbo->bo.mem.bus.offset + gbo->bo.mem.bus.base;
|
||||
info->fix.smem_len = size;
|
||||
return 0;
|
||||
|
||||
out_release_fbi:
|
||||
drm_gem_vram_kunmap(gbo);
|
||||
out_unpin_bo:
|
||||
drm_gem_vram_unpin(gbo);
|
||||
out_unref_gem:
|
||||
drm_gem_object_put_unlocked(gobj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
|
||||
{
|
||||
struct hibmc_framebuffer *gfb = fbdev->fb;
|
||||
struct drm_fb_helper *fbh = &fbdev->helper;
|
||||
|
||||
drm_fb_helper_unregister_fbi(fbh);
|
||||
|
||||
drm_fb_helper_fini(fbh);
|
||||
|
||||
if (gfb)
|
||||
drm_framebuffer_put(&gfb->fb);
|
||||
}
|
||||
|
||||
static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
|
||||
.fb_probe = hibmc_drm_fb_create,
|
||||
};
|
||||
|
||||
int hibmc_fbdev_init(struct hibmc_drm_private *priv)
|
||||
{
|
||||
int ret;
|
||||
struct fb_var_screeninfo *var;
|
||||
struct fb_fix_screeninfo *fix;
|
||||
struct hibmc_fbdev *hifbdev;
|
||||
|
||||
hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL);
|
||||
if (!hifbdev) {
|
||||
DRM_ERROR("failed to allocate hibmc_fbdev\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->fbdev = hifbdev;
|
||||
drm_fb_helper_prepare(priv->dev, &hifbdev->helper,
|
||||
&hibmc_fbdev_helper_funcs);
|
||||
|
||||
/* Now just one crtc and one channel */
|
||||
ret = drm_fb_helper_init(priv->dev, &hifbdev->helper, 1);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize fb helper: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to add all connectors: %d\n", ret);
|
||||
goto fini;
|
||||
}
|
||||
|
||||
ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to setup initial conn config: %d\n", ret);
|
||||
goto fini;
|
||||
}
|
||||
|
||||
var = &hifbdev->helper.fbdev->var;
|
||||
fix = &hifbdev->helper.fbdev->fix;
|
||||
|
||||
DRM_DEBUG_DRIVER("Member of info->var is :\n"
|
||||
"xres=%d\n"
|
||||
"yres=%d\n"
|
||||
"xres_virtual=%d\n"
|
||||
"yres_virtual=%d\n"
|
||||
"xoffset=%d\n"
|
||||
"yoffset=%d\n"
|
||||
"bits_per_pixel=%d\n"
|
||||
"...\n", var->xres, var->yres, var->xres_virtual,
|
||||
var->yres_virtual, var->xoffset, var->yoffset,
|
||||
var->bits_per_pixel);
|
||||
DRM_DEBUG_DRIVER("Member of info->fix is :\n"
|
||||
"smem_start=%lx\n"
|
||||
"smem_len=%d\n"
|
||||
"type=%d\n"
|
||||
"type_aux=%d\n"
|
||||
"visual=%d\n"
|
||||
"xpanstep=%d\n"
|
||||
"ypanstep=%d\n"
|
||||
"ywrapstep=%d\n"
|
||||
"line_length=%d\n"
|
||||
"accel=%d\n"
|
||||
"capabilities=%d\n"
|
||||
"...\n", fix->smem_start, fix->smem_len, fix->type,
|
||||
fix->type_aux, fix->visual, fix->xpanstep,
|
||||
fix->ypanstep, fix->ywrapstep, fix->line_length,
|
||||
fix->accel, fix->capabilities);
|
||||
|
||||
return 0;
|
||||
|
||||
fini:
|
||||
drm_fb_helper_fini(&hifbdev->helper);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hibmc_fbdev_fini(struct hibmc_drm_private *priv)
|
||||
{
|
||||
if (!priv->fbdev)
|
||||
return;
|
||||
|
||||
hibmc_fbdev_destroy(priv->fbdev);
|
||||
priv->fbdev = NULL;
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_gem_vram_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
@ -46,125 +47,14 @@ void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
|
||||
drm_vram_helper_release_mm(hibmc->dev);
|
||||
}
|
||||
|
||||
int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
|
||||
struct drm_gem_object **obj)
|
||||
{
|
||||
struct drm_gem_vram_object *gbo;
|
||||
int ret;
|
||||
|
||||
*obj = NULL;
|
||||
|
||||
size = roundup(size, PAGE_SIZE);
|
||||
if (size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, size, 0, false);
|
||||
if (IS_ERR(gbo)) {
|
||||
ret = PTR_ERR(gbo);
|
||||
if (ret != -ERESTARTSYS)
|
||||
DRM_ERROR("failed to allocate GEM object: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
*obj = &gbo->bo.base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args)
|
||||
{
|
||||
struct drm_gem_object *gobj;
|
||||
u32 handle;
|
||||
int ret;
|
||||
|
||||
args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16);
|
||||
args->size = args->pitch * args->height;
|
||||
|
||||
ret = hibmc_gem_create(dev, args->size, false,
|
||||
&gobj);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create GEM object: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_gem_handle_create(file, gobj, &handle);
|
||||
drm_gem_object_put_unlocked(gobj);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to unreference GEM object: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
args->handle = handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb);
|
||||
|
||||
drm_gem_object_put_unlocked(hibmc_fb->obj);
|
||||
drm_framebuffer_cleanup(fb);
|
||||
kfree(hibmc_fb);
|
||||
}
|
||||
|
||||
static const struct drm_framebuffer_funcs hibmc_fb_funcs = {
|
||||
.destroy = hibmc_user_framebuffer_destroy,
|
||||
};
|
||||
|
||||
struct hibmc_framebuffer *
|
||||
hibmc_framebuffer_init(struct drm_device *dev,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
struct hibmc_framebuffer *hibmc_fb;
|
||||
int ret;
|
||||
|
||||
hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL);
|
||||
if (!hibmc_fb) {
|
||||
DRM_ERROR("failed to allocate hibmc_fb\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
drm_helper_mode_fill_fb_struct(dev, &hibmc_fb->fb, mode_cmd);
|
||||
hibmc_fb->obj = obj;
|
||||
ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs);
|
||||
if (ret) {
|
||||
DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
|
||||
kfree(hibmc_fb);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hibmc_fb;
|
||||
}
|
||||
|
||||
static struct drm_framebuffer *
|
||||
hibmc_user_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_file *filp,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct hibmc_framebuffer *hibmc_fb;
|
||||
|
||||
DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
|
||||
mode_cmd->width, mode_cmd->height,
|
||||
(mode_cmd->pixel_format) & 0xff,
|
||||
(mode_cmd->pixel_format >> 8) & 0xff,
|
||||
(mode_cmd->pixel_format >> 16) & 0xff,
|
||||
(mode_cmd->pixel_format >> 24) & 0xff);
|
||||
|
||||
obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
|
||||
if (!obj)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj);
|
||||
if (IS_ERR(hibmc_fb)) {
|
||||
drm_gem_object_put_unlocked(obj);
|
||||
return ERR_PTR((long)hibmc_fb);
|
||||
}
|
||||
return &hibmc_fb->fb;
|
||||
return drm_gem_vram_fill_create_dumb(file, dev, 0, 16, args);
|
||||
}
|
||||
|
||||
const struct drm_mode_config_funcs hibmc_mode_funcs = {
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
.fb_create = hibmc_user_framebuffer_create,
|
||||
.fb_create = drm_gem_fb_create,
|
||||
};
|
||||
|
@ -413,7 +413,7 @@ void meson_crtc_irq(struct meson_drm *priv)
|
||||
MESON_CANVAS_WRAP_NONE,
|
||||
MESON_CANVAS_BLKMODE_LINEAR,
|
||||
MESON_CANVAS_ENDIAN_SWAP64);
|
||||
};
|
||||
}
|
||||
|
||||
writel_relaxed(priv->viu.vd1_if0_gen_reg,
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
|
@ -237,7 +237,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
|
||||
/* For ARGB, use the pixel's alpha */
|
||||
priv->viu.osd1_ctrl_stat2 &= ~OSD_REPLACE_EN;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
/* Default scaler parameters */
|
||||
vsc_bot_rcv_num = 0;
|
||||
|
@ -208,8 +208,7 @@ int mgag200_cursor_init(struct mga_device *mdev)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ncursors; ++i) {
|
||||
gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev,
|
||||
size, 0, false);
|
||||
gbo = drm_gem_vram_create(dev, size, 0);
|
||||
if (IS_ERR(gbo)) {
|
||||
ret = PTR_ERR(gbo);
|
||||
goto err_drm_gem_vram_put;
|
||||
|
@ -27,6 +27,10 @@ int mgag200_modeset = -1;
|
||||
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
|
||||
module_param_named(modeset, mgag200_modeset, int, 0400);
|
||||
|
||||
int mgag200_hw_bug_no_startadd = -1;
|
||||
MODULE_PARM_DESC(modeset, "HW does not interpret scanout-buffer start address correctly");
|
||||
module_param_named(hw_bug_no_startadd, mgag200_hw_bug_no_startadd, int, 0400);
|
||||
|
||||
static struct drm_driver driver;
|
||||
|
||||
static const struct pci_device_id pciidlist[] = {
|
||||
@ -97,6 +101,16 @@ DEFINE_DRM_GEM_FOPS(mgag200_driver_fops);
|
||||
|
||||
static bool mgag200_pin_bo_at_0(const struct mga_device *mdev)
|
||||
{
|
||||
if (mgag200_hw_bug_no_startadd > 0) {
|
||||
DRM_WARN_ONCE("Option hw_bug_no_startradd is enabled. Please "
|
||||
"report the output of 'lspci -vvnn' to "
|
||||
"<dri-devel@lists.freedesktop.org> if this "
|
||||
"option is required to make mgag200 work "
|
||||
"correctly on your system.\n");
|
||||
return true;
|
||||
} else if (!mgag200_hw_bug_no_startadd) {
|
||||
return false;
|
||||
}
|
||||
return mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD;
|
||||
}
|
||||
|
||||
@ -120,8 +134,7 @@ int mgag200_driver_dumb_create(struct drm_file *file,
|
||||
if (mgag200_pin_bo_at_0(mdev))
|
||||
pg_align = PFN_UP(mdev->mc.vram_size);
|
||||
|
||||
return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev,
|
||||
pg_align, false, args);
|
||||
return drm_gem_vram_fill_create_dumb(file, dev, pg_align, 0, args);
|
||||
}
|
||||
|
||||
static struct drm_driver driver = {
|
||||
|
@ -109,6 +109,17 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
|
||||
24 bit RGB per pixel. It provides a MIPI DSI interface to
|
||||
the host and has a built-in LED backlight.
|
||||
|
||||
config DRM_PANEL_LEADTEK_LTK500HD1829
|
||||
tristate "Leadtek LTK500HD1829 panel"
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
Say Y here if you want to enable support for Kingdisplay kd097d04
|
||||
TFT-LCD modules. The panel has a 1536x2048 resolution and uses
|
||||
24 bit RGB per pixel. It provides a MIPI DSI interface to
|
||||
the host and has a built-in LED backlight.
|
||||
|
||||
config DRM_PANEL_SAMSUNG_LD9040
|
||||
tristate "Samsung LD9040 RGB/SPI panel"
|
||||
depends on OF && SPI
|
||||
@ -366,4 +377,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA
|
||||
help
|
||||
Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI
|
||||
Video Mode panel
|
||||
|
||||
config DRM_PANEL_XINPENG_XPP055C272
|
||||
tristate "Xinpeng XPP055C272 panel driver"
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
Say Y here if you want to enable support for the Xinpeng
|
||||
XPP055C272 controller for 720x1280 LCD panels with MIPI/RGB/SPI
|
||||
system interfaces.
|
||||
endmenu
|
||||
|
@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
|
||||
obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
|
||||
obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
|
||||
obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
|
||||
obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
|
||||
obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
|
||||
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
|
||||
obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
|
||||
@ -39,3 +40,4 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o
|
||||
obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
|
||||
obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
|
||||
obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
|
||||
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o
|
||||
|
531
drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c
Normal file
531
drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c
Normal file
@ -0,0 +1,531 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2019 Theobroma Systems Design und Consulting GmbH
|
||||
*
|
||||
* base on panel-kingdisplay-kd097d04.c
|
||||
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
struct ltk500hd1829 {
|
||||
struct device *dev;
|
||||
struct drm_panel panel;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator *vcc;
|
||||
struct regulator *iovcc;
|
||||
bool prepared;
|
||||
};
|
||||
|
||||
struct ltk500hd1829_cmd {
|
||||
char cmd;
|
||||
char data;
|
||||
};
|
||||
|
||||
/*
|
||||
* There is no description in the Reference Manual about these commands.
|
||||
* We received them from the vendor, so just use them as is.
|
||||
*/
|
||||
static const struct ltk500hd1829_cmd init_code[] = {
|
||||
{ 0xE0, 0x00 },
|
||||
{ 0xE1, 0x93 },
|
||||
{ 0xE2, 0x65 },
|
||||
{ 0xE3, 0xF8 },
|
||||
{ 0x80, 0x03 },
|
||||
{ 0xE0, 0x04 },
|
||||
{ 0x2D, 0x03 },
|
||||
{ 0xE0, 0x01 },
|
||||
{ 0x00, 0x00 },
|
||||
{ 0x01, 0xB6 },
|
||||
{ 0x03, 0x00 },
|
||||
{ 0x04, 0xC5 },
|
||||
{ 0x17, 0x00 },
|
||||
{ 0x18, 0xBF },
|
||||
{ 0x19, 0x01 },
|
||||
{ 0x1A, 0x00 },
|
||||
{ 0x1B, 0xBF },
|
||||
{ 0x1C, 0x01 },
|
||||
{ 0x1F, 0x7C },
|
||||
{ 0x20, 0x26 },
|
||||
{ 0x21, 0x26 },
|
||||
{ 0x22, 0x4E },
|
||||
{ 0x37, 0x09 },
|
||||
{ 0x38, 0x04 },
|
||||
{ 0x39, 0x08 },
|
||||
{ 0x3A, 0x1F },
|
||||
{ 0x3B, 0x1F },
|
||||
{ 0x3C, 0x78 },
|
||||
{ 0x3D, 0xFF },
|
||||
{ 0x3E, 0xFF },
|
||||
{ 0x3F, 0x00 },
|
||||
{ 0x40, 0x04 },
|
||||
{ 0x41, 0xA0 },
|
||||
{ 0x43, 0x0F },
|
||||
{ 0x44, 0x0A },
|
||||
{ 0x45, 0x24 },
|
||||
{ 0x55, 0x01 },
|
||||
{ 0x56, 0x01 },
|
||||
{ 0x57, 0xA5 },
|
||||
{ 0x58, 0x0A },
|
||||
{ 0x59, 0x4A },
|
||||
{ 0x5A, 0x38 },
|
||||
{ 0x5B, 0x10 },
|
||||
{ 0x5C, 0x19 },
|
||||
{ 0x5D, 0x7C },
|
||||
{ 0x5E, 0x64 },
|
||||
{ 0x5F, 0x54 },
|
||||
{ 0x60, 0x48 },
|
||||
{ 0x61, 0x44 },
|
||||
{ 0x62, 0x35 },
|
||||
{ 0x63, 0x3A },
|
||||
{ 0x64, 0x24 },
|
||||
{ 0x65, 0x3B },
|
||||
{ 0x66, 0x39 },
|
||||
{ 0x67, 0x37 },
|
||||
{ 0x68, 0x56 },
|
||||
{ 0x69, 0x41 },
|
||||
{ 0x6A, 0x47 },
|
||||
{ 0x6B, 0x2F },
|
||||
{ 0x6C, 0x23 },
|
||||
{ 0x6D, 0x13 },
|
||||
{ 0x6E, 0x02 },
|
||||
{ 0x6F, 0x08 },
|
||||
{ 0x70, 0x7C },
|
||||
{ 0x71, 0x64 },
|
||||
{ 0x72, 0x54 },
|
||||
{ 0x73, 0x48 },
|
||||
{ 0x74, 0x44 },
|
||||
{ 0x75, 0x35 },
|
||||
{ 0x76, 0x3A },
|
||||
{ 0x77, 0x22 },
|
||||
{ 0x78, 0x3B },
|
||||
{ 0x79, 0x39 },
|
||||
{ 0x7A, 0x38 },
|
||||
{ 0x7B, 0x52 },
|
||||
{ 0x7C, 0x41 },
|
||||
{ 0x7D, 0x47 },
|
||||
{ 0x7E, 0x2F },
|
||||
{ 0x7F, 0x23 },
|
||||
{ 0x80, 0x13 },
|
||||
{ 0x81, 0x02 },
|
||||
{ 0x82, 0x08 },
|
||||
{ 0xE0, 0x02 },
|
||||
{ 0x00, 0x57 },
|
||||
{ 0x01, 0x77 },
|
||||
{ 0x02, 0x44 },
|
||||
{ 0x03, 0x46 },
|
||||
{ 0x04, 0x48 },
|
||||
{ 0x05, 0x4A },
|
||||
{ 0x06, 0x4C },
|
||||
{ 0x07, 0x4E },
|
||||
{ 0x08, 0x50 },
|
||||
{ 0x09, 0x55 },
|
||||
{ 0x0A, 0x52 },
|
||||
{ 0x0B, 0x55 },
|
||||
{ 0x0C, 0x55 },
|
||||
{ 0x0D, 0x55 },
|
||||
{ 0x0E, 0x55 },
|
||||
{ 0x0F, 0x55 },
|
||||
{ 0x10, 0x55 },
|
||||
{ 0x11, 0x55 },
|
||||
{ 0x12, 0x55 },
|
||||
{ 0x13, 0x40 },
|
||||
{ 0x14, 0x55 },
|
||||
{ 0x15, 0x55 },
|
||||
{ 0x16, 0x57 },
|
||||
{ 0x17, 0x77 },
|
||||
{ 0x18, 0x45 },
|
||||
{ 0x19, 0x47 },
|
||||
{ 0x1A, 0x49 },
|
||||
{ 0x1B, 0x4B },
|
||||
{ 0x1C, 0x4D },
|
||||
{ 0x1D, 0x4F },
|
||||
{ 0x1E, 0x51 },
|
||||
{ 0x1F, 0x55 },
|
||||
{ 0x20, 0x53 },
|
||||
{ 0x21, 0x55 },
|
||||
{ 0x22, 0x55 },
|
||||
{ 0x23, 0x55 },
|
||||
{ 0x24, 0x55 },
|
||||
{ 0x25, 0x55 },
|
||||
{ 0x26, 0x55 },
|
||||
{ 0x27, 0x55 },
|
||||
{ 0x28, 0x55 },
|
||||
{ 0x29, 0x41 },
|
||||
{ 0x2A, 0x55 },
|
||||
{ 0x2B, 0x55 },
|
||||
{ 0x2C, 0x57 },
|
||||
{ 0x2D, 0x77 },
|
||||
{ 0x2E, 0x4F },
|
||||
{ 0x2F, 0x4D },
|
||||
{ 0x30, 0x4B },
|
||||
{ 0x31, 0x49 },
|
||||
{ 0x32, 0x47 },
|
||||
{ 0x33, 0x45 },
|
||||
{ 0x34, 0x41 },
|
||||
{ 0x35, 0x55 },
|
||||
{ 0x36, 0x53 },
|
||||
{ 0x37, 0x55 },
|
||||
{ 0x38, 0x55 },
|
||||
{ 0x39, 0x55 },
|
||||
{ 0x3A, 0x55 },
|
||||
{ 0x3B, 0x55 },
|
||||
{ 0x3C, 0x55 },
|
||||
{ 0x3D, 0x55 },
|
||||
{ 0x3E, 0x55 },
|
||||
{ 0x3F, 0x51 },
|
||||
{ 0x40, 0x55 },
|
||||
{ 0x41, 0x55 },
|
||||
{ 0x42, 0x57 },
|
||||
{ 0x43, 0x77 },
|
||||
{ 0x44, 0x4E },
|
||||
{ 0x45, 0x4C },
|
||||
{ 0x46, 0x4A },
|
||||
{ 0x47, 0x48 },
|
||||
{ 0x48, 0x46 },
|
||||
{ 0x49, 0x44 },
|
||||
{ 0x4A, 0x40 },
|
||||
{ 0x4B, 0x55 },
|
||||
{ 0x4C, 0x52 },
|
||||
{ 0x4D, 0x55 },
|
||||
{ 0x4E, 0x55 },
|
||||
{ 0x4F, 0x55 },
|
||||
{ 0x50, 0x55 },
|
||||
{ 0x51, 0x55 },
|
||||
{ 0x52, 0x55 },
|
||||
{ 0x53, 0x55 },
|
||||
{ 0x54, 0x55 },
|
||||
{ 0x55, 0x50 },
|
||||
{ 0x56, 0x55 },
|
||||
{ 0x57, 0x55 },
|
||||
{ 0x58, 0x40 },
|
||||
{ 0x59, 0x00 },
|
||||
{ 0x5A, 0x00 },
|
||||
{ 0x5B, 0x10 },
|
||||
{ 0x5C, 0x09 },
|
||||
{ 0x5D, 0x30 },
|
||||
{ 0x5E, 0x01 },
|
||||
{ 0x5F, 0x02 },
|
||||
{ 0x60, 0x30 },
|
||||
{ 0x61, 0x03 },
|
||||
{ 0x62, 0x04 },
|
||||
{ 0x63, 0x06 },
|
||||
{ 0x64, 0x6A },
|
||||
{ 0x65, 0x75 },
|
||||
{ 0x66, 0x0F },
|
||||
{ 0x67, 0xB3 },
|
||||
{ 0x68, 0x0B },
|
||||
{ 0x69, 0x06 },
|
||||
{ 0x6A, 0x6A },
|
||||
{ 0x6B, 0x10 },
|
||||
{ 0x6C, 0x00 },
|
||||
{ 0x6D, 0x04 },
|
||||
{ 0x6E, 0x04 },
|
||||
{ 0x6F, 0x88 },
|
||||
{ 0x70, 0x00 },
|
||||
{ 0x71, 0x00 },
|
||||
{ 0x72, 0x06 },
|
||||
{ 0x73, 0x7B },
|
||||
{ 0x74, 0x00 },
|
||||
{ 0x75, 0xBC },
|
||||
{ 0x76, 0x00 },
|
||||
{ 0x77, 0x05 },
|
||||
{ 0x78, 0x2E },
|
||||
{ 0x79, 0x00 },
|
||||
{ 0x7A, 0x00 },
|
||||
{ 0x7B, 0x00 },
|
||||
{ 0x7C, 0x00 },
|
||||
{ 0x7D, 0x03 },
|
||||
{ 0x7E, 0x7B },
|
||||
{ 0xE0, 0x04 },
|
||||
{ 0x09, 0x10 },
|
||||
{ 0x2B, 0x2B },
|
||||
{ 0x2E, 0x44 },
|
||||
{ 0xE0, 0x00 },
|
||||
{ 0xE6, 0x02 },
|
||||
{ 0xE7, 0x02 },
|
||||
{ 0x35, 0x00 },
|
||||
};
|
||||
|
||||
static inline
|
||||
struct ltk500hd1829 *panel_to_ltk500hd1829(struct drm_panel *panel)
|
||||
{
|
||||
return container_of(panel, struct ltk500hd1829, panel);
|
||||
}
|
||||
|
||||
static int ltk500hd1829_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel);
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
int ret;
|
||||
|
||||
if (!ctx->prepared)
|
||||
return 0;
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_off(dsi);
|
||||
if (ret < 0)
|
||||
DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
|
||||
ret);
|
||||
|
||||
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
/* 120ms to enter sleep mode */
|
||||
msleep(120);
|
||||
|
||||
regulator_disable(ctx->iovcc);
|
||||
regulator_disable(ctx->vcc);
|
||||
|
||||
ctx->prepared = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltk500hd1829_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel);
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (ctx->prepared)
|
||||
return 0;
|
||||
|
||||
ret = regulator_enable(ctx->vcc);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev,
|
||||
"Failed to enable vci supply: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = regulator_enable(ctx->iovcc);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev,
|
||||
"Failed to enable iovcc supply: %d\n", ret);
|
||||
goto disable_vcc;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
/* tRW: 10us */
|
||||
usleep_range(10, 20);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||
|
||||
/* tRT: >= 5ms */
|
||||
usleep_range(5000, 6000);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(init_code); i++) {
|
||||
ret = mipi_dsi_generic_write(dsi, &init_code[i],
|
||||
sizeof(struct ltk500hd1829_cmd));
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(panel->dev,
|
||||
"failed to write init cmds: %d\n", ret);
|
||||
goto disable_iovcc;
|
||||
}
|
||||
}
|
||||
|
||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
|
||||
ret);
|
||||
goto disable_iovcc;
|
||||
}
|
||||
|
||||
/* 120ms to exit sleep mode */
|
||||
msleep(120);
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_on(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
|
||||
ret);
|
||||
goto disable_iovcc;
|
||||
}
|
||||
|
||||
ctx->prepared = true;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_iovcc:
|
||||
regulator_disable(ctx->iovcc);
|
||||
disable_vcc:
|
||||
regulator_disable(ctx->vcc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_display_mode default_mode = {
|
||||
.hdisplay = 720,
|
||||
.hsync_start = 720 + 50,
|
||||
.hsync_end = 720 + 50 + 50,
|
||||
.htotal = 720 + 50 + 50 + 50,
|
||||
.vdisplay = 1280,
|
||||
.vsync_start = 1280 + 30,
|
||||
.vsync_end = 1280 + 30 + 4,
|
||||
.vtotal = 1280 + 30 + 4 + 12,
|
||||
.vrefresh = 60,
|
||||
.clock = 41600,
|
||||
.width_mm = 62,
|
||||
.height_mm = 110,
|
||||
};
|
||||
|
||||
static int ltk500hd1829_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel);
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
mode = drm_mode_duplicate(connector->dev, &default_mode);
|
||||
if (!mode) {
|
||||
DRM_DEV_ERROR(ctx->dev, "failed to add mode %ux%ux@%u\n",
|
||||
default_mode.hdisplay, default_mode.vdisplay,
|
||||
default_mode.vrefresh);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
|
||||
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||
connector->display_info.width_mm = mode->width_mm;
|
||||
connector->display_info.height_mm = mode->height_mm;
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs ltk500hd1829_funcs = {
|
||||
.unprepare = ltk500hd1829_unprepare,
|
||||
.prepare = ltk500hd1829_prepare,
|
||||
.get_modes = ltk500hd1829_get_modes,
|
||||
};
|
||||
|
||||
static int ltk500hd1829_probe(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct ltk500hd1829 *ctx;
|
||||
struct device *dev = &dsi->dev;
|
||||
int ret;
|
||||
|
||||
ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->reset_gpio)) {
|
||||
DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
|
||||
return PTR_ERR(ctx->reset_gpio);
|
||||
}
|
||||
|
||||
ctx->vcc = devm_regulator_get(dev, "vcc");
|
||||
if (IS_ERR(ctx->vcc)) {
|
||||
ret = PTR_ERR(ctx->vcc);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
DRM_DEV_ERROR(dev,
|
||||
"Failed to request vcc regulator: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx->iovcc = devm_regulator_get(dev, "iovcc");
|
||||
if (IS_ERR(ctx->iovcc)) {
|
||||
ret = PTR_ERR(ctx->iovcc);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
DRM_DEV_ERROR(dev,
|
||||
"Failed to request iovcc regulator: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_set_drvdata(dsi, ctx);
|
||||
|
||||
ctx->dev = dev;
|
||||
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET;
|
||||
|
||||
drm_panel_init(&ctx->panel, &dsi->dev, <k500hd1829_funcs,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
|
||||
ret = drm_panel_of_backlight(&ctx->panel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_panel_add(&ctx->panel);
|
||||
|
||||
ret = mipi_dsi_attach(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret);
|
||||
drm_panel_remove(&ctx->panel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ltk500hd1829_shutdown(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct ltk500hd1829 *ctx = mipi_dsi_get_drvdata(dsi);
|
||||
int ret;
|
||||
|
||||
ret = drm_panel_unprepare(&ctx->panel);
|
||||
if (ret < 0)
|
||||
DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
|
||||
ret);
|
||||
|
||||
ret = drm_panel_disable(&ctx->panel);
|
||||
if (ret < 0)
|
||||
DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
static int ltk500hd1829_remove(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct ltk500hd1829 *ctx = mipi_dsi_get_drvdata(dsi);
|
||||
int ret;
|
||||
|
||||
ltk500hd1829_shutdown(dsi);
|
||||
|
||||
ret = mipi_dsi_detach(dsi);
|
||||
if (ret < 0)
|
||||
DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
|
||||
ret);
|
||||
|
||||
drm_panel_remove(&ctx->panel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ltk500hd1829_of_match[] = {
|
||||
{ .compatible = "leadtek,ltk500hd1829", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltk500hd1829_of_match);
|
||||
|
||||
static struct mipi_dsi_driver ltk500hd1829_driver = {
|
||||
.driver = {
|
||||
.name = "panel-leadtek-ltk500hd1829",
|
||||
.of_match_table = ltk500hd1829_of_match,
|
||||
},
|
||||
.probe = ltk500hd1829_probe,
|
||||
.remove = ltk500hd1829_remove,
|
||||
.shutdown = ltk500hd1829_shutdown,
|
||||
};
|
||||
module_mipi_dsi_driver(ltk500hd1829_driver);
|
||||
|
||||
MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
|
||||
MODULE_DESCRIPTION("Leadtek LTK500HD1829 panel driver");
|
||||
MODULE_LICENSE("GPL v2");
|
398
drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c
Normal file
398
drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c
Normal file
@ -0,0 +1,398 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Xinpeng xpp055c272 5.5" MIPI-DSI panel driver
|
||||
* Copyright (C) 2019 Theobroma Systems Design und Consulting GmbH
|
||||
*
|
||||
* based on
|
||||
*
|
||||
* Rockteck jh057n00900 5.5" MIPI-DSI panel driver
|
||||
* Copyright (C) Purism SPC 2019
|
||||
*/
|
||||
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include <video/display_timing.h>
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/media-bus-format.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/* Manufacturer specific Commands send via DSI */
|
||||
#define XPP055C272_CMD_ALL_PIXEL_OFF 0x22
|
||||
#define XPP055C272_CMD_ALL_PIXEL_ON 0x23
|
||||
#define XPP055C272_CMD_SETDISP 0xb2
|
||||
#define XPP055C272_CMD_SETRGBIF 0xb3
|
||||
#define XPP055C272_CMD_SETCYC 0xb4
|
||||
#define XPP055C272_CMD_SETBGP 0xb5
|
||||
#define XPP055C272_CMD_SETVCOM 0xb6
|
||||
#define XPP055C272_CMD_SETOTP 0xb7
|
||||
#define XPP055C272_CMD_SETPOWER_EXT 0xb8
|
||||
#define XPP055C272_CMD_SETEXTC 0xb9
|
||||
#define XPP055C272_CMD_SETMIPI 0xbA
|
||||
#define XPP055C272_CMD_SETVDC 0xbc
|
||||
#define XPP055C272_CMD_SETPCR 0xbf
|
||||
#define XPP055C272_CMD_SETSCR 0xc0
|
||||
#define XPP055C272_CMD_SETPOWER 0xc1
|
||||
#define XPP055C272_CMD_SETECO 0xc6
|
||||
#define XPP055C272_CMD_SETPANEL 0xcc
|
||||
#define XPP055C272_CMD_SETGAMMA 0xe0
|
||||
#define XPP055C272_CMD_SETEQ 0xe3
|
||||
#define XPP055C272_CMD_SETGIP1 0xe9
|
||||
#define XPP055C272_CMD_SETGIP2 0xea
|
||||
|
||||
struct xpp055c272 {
|
||||
struct device *dev;
|
||||
struct drm_panel panel;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator *vci;
|
||||
struct regulator *iovcc;
|
||||
bool prepared;
|
||||
};
|
||||
|
||||
static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel)
|
||||
{
|
||||
return container_of(panel, struct xpp055c272, panel);
|
||||
}
|
||||
|
||||
#define dsi_generic_write_seq(dsi, cmd, seq...) do { \
|
||||
static const u8 d[] = { seq }; \
|
||||
int ret; \
|
||||
ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
|
||||
if (ret < 0) \
|
||||
return ret; \
|
||||
} while (0)
|
||||
|
||||
static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
struct device *dev = ctx->dev;
|
||||
|
||||
/*
|
||||
* Init sequence was supplied by the panel vendor without much
|
||||
* documentation.
|
||||
*/
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETMIPI,
|
||||
0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
|
||||
0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01,
|
||||
0x00, 0x00, 0x37);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETRGBIF,
|
||||
0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETSCR,
|
||||
0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
|
||||
0x00);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEQ,
|
||||
0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER,
|
||||
0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd,
|
||||
0x67, 0x77, 0x33, 0x33);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff,
|
||||
0xff, 0x01, 0xff);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
|
||||
msleep(20);
|
||||
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP1,
|
||||
0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12,
|
||||
0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18,
|
||||
0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42,
|
||||
0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58,
|
||||
0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88,
|
||||
0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP2,
|
||||
0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35,
|
||||
0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f,
|
||||
0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88,
|
||||
0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05,
|
||||
0xa0, 0x00, 0x00, 0x00, 0x00);
|
||||
dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGAMMA,
|
||||
0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36,
|
||||
0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11,
|
||||
0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38,
|
||||
0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13,
|
||||
0x11, 0x18);
|
||||
|
||||
msleep(60);
|
||||
|
||||
DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xpp055c272_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
int ret;
|
||||
|
||||
if (!ctx->prepared)
|
||||
return 0;
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_off(dsi);
|
||||
if (ret < 0)
|
||||
DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n",
|
||||
ret);
|
||||
|
||||
mipi_dsi_dcs_enter_sleep_mode(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regulator_disable(ctx->iovcc);
|
||||
regulator_disable(ctx->vci);
|
||||
|
||||
ctx->prepared = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xpp055c272_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
int ret;
|
||||
|
||||
if (ctx->prepared)
|
||||
return 0;
|
||||
|
||||
DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
|
||||
ret = regulator_enable(ctx->vci);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev,
|
||||
"Failed to enable vci supply: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = regulator_enable(ctx->iovcc);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev,
|
||||
"Failed to enable iovcc supply: %d\n", ret);
|
||||
goto disable_vci;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
/* T6: 10us */
|
||||
usleep_range(10, 20);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||
|
||||
/* T8: 20ms */
|
||||
msleep(20);
|
||||
|
||||
ret = xpp055c272_init_sequence(ctx);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
|
||||
ret);
|
||||
goto disable_iovcc;
|
||||
}
|
||||
|
||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
|
||||
goto disable_iovcc;
|
||||
}
|
||||
|
||||
/* T9: 120ms */
|
||||
msleep(120);
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_on(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret);
|
||||
goto disable_iovcc;
|
||||
}
|
||||
|
||||
msleep(50);
|
||||
|
||||
ctx->prepared = true;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_iovcc:
|
||||
regulator_disable(ctx->iovcc);
|
||||
disable_vci:
|
||||
regulator_disable(ctx->vci);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_display_mode default_mode = {
|
||||
.hdisplay = 720,
|
||||
.hsync_start = 720 + 40,
|
||||
.hsync_end = 720 + 40 + 10,
|
||||
.htotal = 720 + 40 + 10 + 40,
|
||||
.vdisplay = 1280,
|
||||
.vsync_start = 1280 + 22,
|
||||
.vsync_end = 1280 + 22 + 4,
|
||||
.vtotal = 1280 + 22 + 4 + 11,
|
||||
.vrefresh = 60,
|
||||
.clock = 64000,
|
||||
.width_mm = 68,
|
||||
.height_mm = 121,
|
||||
};
|
||||
|
||||
static int xpp055c272_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
mode = drm_mode_duplicate(connector->dev, &default_mode);
|
||||
if (!mode) {
|
||||
DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
|
||||
default_mode.hdisplay, default_mode.vdisplay,
|
||||
default_mode.vrefresh);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
|
||||
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||
connector->display_info.width_mm = mode->width_mm;
|
||||
connector->display_info.height_mm = mode->height_mm;
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs xpp055c272_funcs = {
|
||||
.unprepare = xpp055c272_unprepare,
|
||||
.prepare = xpp055c272_prepare,
|
||||
.get_modes = xpp055c272_get_modes,
|
||||
};
|
||||
|
||||
static int xpp055c272_probe(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct device *dev = &dsi->dev;
|
||||
struct xpp055c272 *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->reset_gpio)) {
|
||||
DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
|
||||
return PTR_ERR(ctx->reset_gpio);
|
||||
}
|
||||
|
||||
ctx->vci = devm_regulator_get(dev, "vci");
|
||||
if (IS_ERR(ctx->vci)) {
|
||||
ret = PTR_ERR(ctx->vci);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
DRM_DEV_ERROR(dev,
|
||||
"Failed to request vci regulator: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx->iovcc = devm_regulator_get(dev, "iovcc");
|
||||
if (IS_ERR(ctx->iovcc)) {
|
||||
ret = PTR_ERR(ctx->iovcc);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
DRM_DEV_ERROR(dev,
|
||||
"Failed to request iovcc regulator: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_set_drvdata(dsi, ctx);
|
||||
|
||||
ctx->dev = dev;
|
||||
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET;
|
||||
|
||||
drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
|
||||
ret = drm_panel_of_backlight(&ctx->panel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_panel_add(&ctx->panel);
|
||||
|
||||
ret = mipi_dsi_attach(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret);
|
||||
drm_panel_remove(&ctx->panel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xpp055c272_shutdown(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
|
||||
int ret;
|
||||
|
||||
ret = drm_panel_unprepare(&ctx->panel);
|
||||
if (ret < 0)
|
||||
DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
|
||||
ret);
|
||||
|
||||
ret = drm_panel_disable(&ctx->panel);
|
||||
if (ret < 0)
|
||||
DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
static int xpp055c272_remove(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
|
||||
int ret;
|
||||
|
||||
xpp055c272_shutdown(dsi);
|
||||
|
||||
ret = mipi_dsi_detach(dsi);
|
||||
if (ret < 0)
|
||||
DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
|
||||
ret);
|
||||
|
||||
drm_panel_remove(&ctx->panel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id xpp055c272_of_match[] = {
|
||||
{ .compatible = "xinpeng,xpp055c272" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xpp055c272_of_match);
|
||||
|
||||
static struct mipi_dsi_driver xpp055c272_driver = {
|
||||
.driver = {
|
||||
.name = "panel-xinpeng-xpp055c272",
|
||||
.of_match_table = xpp055c272_of_match,
|
||||
},
|
||||
.probe = xpp055c272_probe,
|
||||
.remove = xpp055c272_remove,
|
||||
.shutdown = xpp055c272_shutdown,
|
||||
};
|
||||
module_mipi_dsi_driver(xpp055c272_driver);
|
||||
|
||||
MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
|
||||
MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -590,8 +590,9 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge,
|
||||
}
|
||||
|
||||
static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state)
|
||||
struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
struct drm_atomic_state *state = old_bridge_state->base.state;
|
||||
struct drm_connector *connector;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
@ -603,7 +604,7 @@ static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
|
||||
}
|
||||
|
||||
static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state)
|
||||
struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
|
||||
|
||||
@ -618,7 +619,8 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
|
||||
|
||||
/* Disable the companion LVDS encoder in dual-link mode. */
|
||||
if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion)
|
||||
lvds->companion->funcs->atomic_disable(lvds->companion, state);
|
||||
lvds->companion->funcs->atomic_disable(lvds->companion,
|
||||
old_bridge_state);
|
||||
|
||||
clk_disable_unprepare(lvds->clocks.mod);
|
||||
}
|
||||
|
@ -641,6 +641,9 @@ static int rk3066_hdmi_i2c_write(struct rk3066_hdmi *hdmi, struct i2c_msg *msgs)
|
||||
if (msgs->addr == DDC_ADDR)
|
||||
hdmi->i2c->ddc_addr = msgs->buf[0];
|
||||
|
||||
/* Set edid fifo first address. */
|
||||
hdmi_writeb(hdmi, HDMI_EDID_FIFO_ADDR, 0x00);
|
||||
|
||||
/* Set edid word address 0x00/0x80. */
|
||||
hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/component.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/pinctrl/devinfo.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -31,6 +32,8 @@
|
||||
#define DISPLAY_OUTPUT_LVDS 1
|
||||
#define DISPLAY_OUTPUT_DUAL_LVDS 2
|
||||
|
||||
struct rockchip_lvds;
|
||||
|
||||
#define connector_to_lvds(c) \
|
||||
container_of(c, struct rockchip_lvds, connector)
|
||||
|
||||
@ -39,16 +42,12 @@
|
||||
|
||||
/**
|
||||
* rockchip_lvds_soc_data - rockchip lvds Soc private data
|
||||
* @ch1_offset: lvds channel 1 registe offset
|
||||
* grf_soc_con6: general registe offset for LVDS contrl
|
||||
* grf_soc_con7: general registe offset for LVDS contrl
|
||||
* has_vop_sel: to indicate whether need to choose from different VOP.
|
||||
* @probe: LVDS platform probe function
|
||||
* @helper_funcs: LVDS connector helper functions
|
||||
*/
|
||||
struct rockchip_lvds_soc_data {
|
||||
u32 ch1_offset;
|
||||
int grf_soc_con6;
|
||||
int grf_soc_con7;
|
||||
bool has_vop_sel;
|
||||
int (*probe)(struct platform_device *pdev, struct rockchip_lvds *lvds);
|
||||
const struct drm_encoder_helper_funcs *helper_funcs;
|
||||
};
|
||||
|
||||
struct rockchip_lvds {
|
||||
@ -56,6 +55,7 @@ struct rockchip_lvds {
|
||||
void __iomem *regs;
|
||||
struct regmap *grf;
|
||||
struct clk *pclk;
|
||||
struct phy *dphy;
|
||||
const struct rockchip_lvds_soc_data *soc_data;
|
||||
int output; /* rgb lvds or dual lvds output */
|
||||
int format; /* vesa or jeida format */
|
||||
@ -67,15 +67,16 @@ struct rockchip_lvds {
|
||||
struct dev_pin_info *pins;
|
||||
};
|
||||
|
||||
static inline void lvds_writel(struct rockchip_lvds *lvds, u32 offset, u32 val)
|
||||
static inline void rk3288_writel(struct rockchip_lvds *lvds, u32 offset,
|
||||
u32 val)
|
||||
{
|
||||
writel_relaxed(val, lvds->regs + offset);
|
||||
if (lvds->output == DISPLAY_OUTPUT_LVDS)
|
||||
return;
|
||||
writel_relaxed(val, lvds->regs + offset + lvds->soc_data->ch1_offset);
|
||||
writel_relaxed(val, lvds->regs + offset + RK3288_LVDS_CH1_OFFSET);
|
||||
}
|
||||
|
||||
static inline int lvds_name_to_format(const char *s)
|
||||
static inline int rockchip_lvds_name_to_format(const char *s)
|
||||
{
|
||||
if (strncmp(s, "jeida-18", 8) == 0)
|
||||
return LVDS_JEIDA_18;
|
||||
@ -87,7 +88,7 @@ static inline int lvds_name_to_format(const char *s)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int lvds_name_to_output(const char *s)
|
||||
static inline int rockchip_lvds_name_to_output(const char *s)
|
||||
{
|
||||
if (strncmp(s, "rgb", 3) == 0)
|
||||
return DISPLAY_OUTPUT_RGB;
|
||||
@ -99,95 +100,6 @@ static inline int lvds_name_to_output(const char *s)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rockchip_lvds_poweron(struct rockchip_lvds *lvds)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
ret = clk_enable(lvds->pclk);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = pm_runtime_get_sync(lvds->dev);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret);
|
||||
clk_disable(lvds->pclk);
|
||||
return ret;
|
||||
}
|
||||
val = RK3288_LVDS_CH0_REG0_LANE4_EN | RK3288_LVDS_CH0_REG0_LANE3_EN |
|
||||
RK3288_LVDS_CH0_REG0_LANE2_EN | RK3288_LVDS_CH0_REG0_LANE1_EN |
|
||||
RK3288_LVDS_CH0_REG0_LANE0_EN;
|
||||
if (lvds->output == DISPLAY_OUTPUT_RGB) {
|
||||
val |= RK3288_LVDS_CH0_REG0_TTL_EN |
|
||||
RK3288_LVDS_CH0_REG0_LANECK_EN;
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG0, val);
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG2,
|
||||
RK3288_LVDS_PLL_FBDIV_REG2(0x46));
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG4,
|
||||
RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG5,
|
||||
RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
|
||||
} else {
|
||||
val |= RK3288_LVDS_CH0_REG0_LVDS_EN |
|
||||
RK3288_LVDS_CH0_REG0_LANECK_EN;
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG0, val);
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG1,
|
||||
RK3288_LVDS_CH0_REG1_LANECK_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE4_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE3_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE2_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE1_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE0_BIAS);
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG2,
|
||||
RK3288_LVDS_CH0_REG2_RESERVE_ON |
|
||||
RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
|
||||
RK3288_LVDS_PLL_FBDIV_REG2(0x46));
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00);
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00);
|
||||
}
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG3, RK3288_LVDS_PLL_FBDIV_REG3(0x46));
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REGD, RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
|
||||
lvds_writel(lvds, RK3288_LVDS_CH0_REG20, RK3288_LVDS_CH0_REG20_LSB);
|
||||
|
||||
lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE);
|
||||
lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
lvds_writel(lvds, RK3288_LVDS_CFG_REG21, RK3288_LVDS_CFG_REG21_TX_ENABLE);
|
||||
lvds_writel(lvds, RK3288_LVDS_CFG_REGC, RK3288_LVDS_CFG_REGC_PLL_ENABLE);
|
||||
val = LVDS_DUAL | LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN | LVDS_PWRDN;
|
||||
val |= val << 16;
|
||||
ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val);
|
||||
if (ret != 0)
|
||||
DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret);
|
||||
|
||||
pm_runtime_put(lvds->dev);
|
||||
clk_disable(lvds->pclk);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs rockchip_lvds_connector_funcs = {
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
@ -209,8 +121,117 @@ struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = {
|
||||
.get_modes = rockchip_lvds_connector_get_modes,
|
||||
};
|
||||
|
||||
static void rockchip_lvds_grf_config(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
static int
|
||||
rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
||||
|
||||
s->output_mode = ROCKCHIP_OUT_MODE_P888;
|
||||
s->output_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3288_lvds_poweron(struct rockchip_lvds *lvds)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
ret = clk_enable(lvds->pclk);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = pm_runtime_get_sync(lvds->dev);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret);
|
||||
clk_disable(lvds->pclk);
|
||||
return ret;
|
||||
}
|
||||
val = RK3288_LVDS_CH0_REG0_LANE4_EN | RK3288_LVDS_CH0_REG0_LANE3_EN |
|
||||
RK3288_LVDS_CH0_REG0_LANE2_EN | RK3288_LVDS_CH0_REG0_LANE1_EN |
|
||||
RK3288_LVDS_CH0_REG0_LANE0_EN;
|
||||
if (lvds->output == DISPLAY_OUTPUT_RGB) {
|
||||
val |= RK3288_LVDS_CH0_REG0_TTL_EN |
|
||||
RK3288_LVDS_CH0_REG0_LANECK_EN;
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG0, val);
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG2,
|
||||
RK3288_LVDS_PLL_FBDIV_REG2(0x46));
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG4,
|
||||
RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
|
||||
RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG5,
|
||||
RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
|
||||
RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
|
||||
} else {
|
||||
val |= RK3288_LVDS_CH0_REG0_LVDS_EN |
|
||||
RK3288_LVDS_CH0_REG0_LANECK_EN;
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG0, val);
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG1,
|
||||
RK3288_LVDS_CH0_REG1_LANECK_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE4_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE3_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE2_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE1_BIAS |
|
||||
RK3288_LVDS_CH0_REG1_LANE0_BIAS);
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG2,
|
||||
RK3288_LVDS_CH0_REG2_RESERVE_ON |
|
||||
RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
|
||||
RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
|
||||
RK3288_LVDS_PLL_FBDIV_REG2(0x46));
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00);
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00);
|
||||
}
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG3,
|
||||
RK3288_LVDS_PLL_FBDIV_REG3(0x46));
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REGD,
|
||||
RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
|
||||
rk3288_writel(lvds, RK3288_LVDS_CH0_REG20,
|
||||
RK3288_LVDS_CH0_REG20_LSB);
|
||||
|
||||
rk3288_writel(lvds, RK3288_LVDS_CFG_REGC,
|
||||
RK3288_LVDS_CFG_REGC_PLL_ENABLE);
|
||||
rk3288_writel(lvds, RK3288_LVDS_CFG_REG21,
|
||||
RK3288_LVDS_CFG_REG21_TX_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk3288_lvds_poweroff(struct rockchip_lvds *lvds)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
rk3288_writel(lvds, RK3288_LVDS_CFG_REG21,
|
||||
RK3288_LVDS_CFG_REG21_TX_ENABLE);
|
||||
rk3288_writel(lvds, RK3288_LVDS_CFG_REGC,
|
||||
RK3288_LVDS_CFG_REGC_PLL_ENABLE);
|
||||
val = LVDS_DUAL | LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN | LVDS_PWRDN;
|
||||
val |= val << 16;
|
||||
ret = regmap_write(lvds->grf, RK3288_LVDS_GRF_SOC_CON7, val);
|
||||
if (ret != 0)
|
||||
DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret);
|
||||
|
||||
pm_runtime_put(lvds->dev);
|
||||
clk_disable(lvds->pclk);
|
||||
}
|
||||
|
||||
static int rk3288_lvds_grf_config(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
|
||||
u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0;
|
||||
@ -234,22 +255,19 @@ static void rockchip_lvds_grf_config(struct drm_encoder *encoder,
|
||||
|
||||
val |= (pin_dclk << 8) | (pin_hsync << 9);
|
||||
val |= (0xffff << 16);
|
||||
ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val);
|
||||
if (ret != 0) {
|
||||
ret = regmap_write(lvds->grf, RK3288_LVDS_GRF_SOC_CON7, val);
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(lvds->dev, "Could not write to GRF: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds,
|
||||
struct drm_encoder *encoder)
|
||||
static int rk3288_lvds_set_vop_source(struct rockchip_lvds *lvds,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!lvds->soc_data->has_vop_sel)
|
||||
return 0;
|
||||
|
||||
ret = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -258,56 +276,162 @@ static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds,
|
||||
if (ret)
|
||||
val |= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT;
|
||||
|
||||
ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val);
|
||||
ret = regmap_write(lvds->grf, RK3288_LVDS_GRF_SOC_CON6, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
||||
|
||||
s->output_mode = ROCKCHIP_OUT_MODE_P888;
|
||||
s->output_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_lvds_encoder_enable(struct drm_encoder *encoder)
|
||||
static void rk3288_lvds_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
|
||||
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
int ret;
|
||||
|
||||
drm_panel_prepare(lvds->panel);
|
||||
ret = rockchip_lvds_poweron(lvds);
|
||||
|
||||
ret = rk3288_lvds_poweron(lvds);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to power on lvds: %d\n", ret);
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to power on LVDS: %d\n", ret);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
return;
|
||||
}
|
||||
rockchip_lvds_grf_config(encoder, mode);
|
||||
rockchip_lvds_set_vop_source(lvds, encoder);
|
||||
|
||||
ret = rk3288_lvds_grf_config(encoder, mode);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to configure LVDS: %d\n", ret);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = rk3288_lvds_set_vop_source(lvds, encoder);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to set VOP source: %d\n", ret);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
return;
|
||||
}
|
||||
|
||||
drm_panel_enable(lvds->panel);
|
||||
}
|
||||
|
||||
static void rockchip_lvds_encoder_disable(struct drm_encoder *encoder)
|
||||
static void rk3288_lvds_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
|
||||
|
||||
drm_panel_disable(lvds->panel);
|
||||
rockchip_lvds_poweroff(lvds);
|
||||
rk3288_lvds_poweroff(lvds);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
}
|
||||
|
||||
static int px30_lvds_poweron(struct rockchip_lvds *lvds)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(lvds->dev);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable LVDS mode */
|
||||
return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
|
||||
PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1),
|
||||
PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1));
|
||||
}
|
||||
|
||||
static void px30_lvds_poweroff(struct rockchip_lvds *lvds)
|
||||
{
|
||||
regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
|
||||
PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1),
|
||||
PX30_LVDS_MODE_EN(0) | PX30_LVDS_P2S_EN(0));
|
||||
|
||||
pm_runtime_put(lvds->dev);
|
||||
}
|
||||
|
||||
static int px30_lvds_grf_config(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
|
||||
|
||||
if (lvds->output != DISPLAY_OUTPUT_LVDS) {
|
||||
DRM_DEV_ERROR(lvds->dev, "Unsupported display output %d\n",
|
||||
lvds->output);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set format */
|
||||
return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
|
||||
PX30_LVDS_FORMAT(lvds->format),
|
||||
PX30_LVDS_FORMAT(lvds->format));
|
||||
}
|
||||
|
||||
static int px30_lvds_set_vop_source(struct rockchip_lvds *lvds,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
int vop;
|
||||
|
||||
vop = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder);
|
||||
if (vop < 0)
|
||||
return vop;
|
||||
|
||||
return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
|
||||
PX30_LVDS_VOP_SEL(1),
|
||||
PX30_LVDS_VOP_SEL(vop));
|
||||
}
|
||||
|
||||
static void px30_lvds_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
|
||||
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
int ret;
|
||||
|
||||
drm_panel_prepare(lvds->panel);
|
||||
|
||||
ret = px30_lvds_poweron(lvds);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to power on LVDS: %d\n", ret);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = px30_lvds_grf_config(encoder, mode);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to configure LVDS: %d\n", ret);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = px30_lvds_set_vop_source(lvds, encoder);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to set VOP source: %d\n", ret);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
return;
|
||||
}
|
||||
|
||||
drm_panel_enable(lvds->panel);
|
||||
}
|
||||
|
||||
static void px30_lvds_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
|
||||
|
||||
drm_panel_disable(lvds->panel);
|
||||
px30_lvds_poweroff(lvds);
|
||||
drm_panel_unprepare(lvds->panel);
|
||||
}
|
||||
|
||||
static const
|
||||
struct drm_encoder_helper_funcs rockchip_lvds_encoder_helper_funcs = {
|
||||
.enable = rockchip_lvds_encoder_enable,
|
||||
.disable = rockchip_lvds_encoder_disable,
|
||||
struct drm_encoder_helper_funcs rk3288_lvds_encoder_helper_funcs = {
|
||||
.enable = rk3288_lvds_encoder_enable,
|
||||
.disable = rk3288_lvds_encoder_disable,
|
||||
.atomic_check = rockchip_lvds_encoder_atomic_check,
|
||||
};
|
||||
|
||||
static const
|
||||
struct drm_encoder_helper_funcs px30_lvds_encoder_helper_funcs = {
|
||||
.enable = px30_lvds_encoder_enable,
|
||||
.disable = px30_lvds_encoder_disable,
|
||||
.atomic_check = rockchip_lvds_encoder_atomic_check,
|
||||
};
|
||||
|
||||
@ -315,11 +439,88 @@ static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static int rk3288_lvds_probe(struct platform_device *pdev,
|
||||
struct rockchip_lvds *lvds)
|
||||
{
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
lvds->regs = devm_ioremap_resource(lvds->dev, res);
|
||||
if (IS_ERR(lvds->regs))
|
||||
return PTR_ERR(lvds->regs);
|
||||
|
||||
lvds->pclk = devm_clk_get(lvds->dev, "pclk_lvds");
|
||||
if (IS_ERR(lvds->pclk)) {
|
||||
DRM_DEV_ERROR(lvds->dev, "could not get pclk_lvds\n");
|
||||
return PTR_ERR(lvds->pclk);
|
||||
}
|
||||
|
||||
lvds->pins = devm_kzalloc(lvds->dev, sizeof(*lvds->pins),
|
||||
GFP_KERNEL);
|
||||
if (!lvds->pins)
|
||||
return -ENOMEM;
|
||||
|
||||
lvds->pins->p = devm_pinctrl_get(lvds->dev);
|
||||
if (IS_ERR(lvds->pins->p)) {
|
||||
DRM_DEV_ERROR(lvds->dev, "no pinctrl handle\n");
|
||||
devm_kfree(lvds->dev, lvds->pins);
|
||||
lvds->pins = NULL;
|
||||
} else {
|
||||
lvds->pins->default_state =
|
||||
pinctrl_lookup_state(lvds->pins->p, "lcdc");
|
||||
if (IS_ERR(lvds->pins->default_state)) {
|
||||
DRM_DEV_ERROR(lvds->dev, "no default pinctrl state\n");
|
||||
devm_kfree(lvds->dev, lvds->pins);
|
||||
lvds->pins = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_prepare(lvds->pclk);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(lvds->dev, "failed to prepare pclk_lvds\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int px30_lvds_probe(struct platform_device *pdev,
|
||||
struct rockchip_lvds *lvds)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* MSB */
|
||||
ret = regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1,
|
||||
PX30_LVDS_MSBSEL(1),
|
||||
PX30_LVDS_MSBSEL(1));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* PHY */
|
||||
lvds->dphy = devm_phy_get(&pdev->dev, "dphy");
|
||||
if (IS_ERR(lvds->dphy))
|
||||
return PTR_ERR(lvds->dphy);
|
||||
|
||||
phy_init(lvds->dphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
phy_set_mode(lvds->dphy, PHY_MODE_LVDS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return phy_power_on(lvds->dphy);
|
||||
}
|
||||
|
||||
static const struct rockchip_lvds_soc_data rk3288_lvds_data = {
|
||||
.ch1_offset = 0x100,
|
||||
.grf_soc_con6 = 0x025c,
|
||||
.grf_soc_con7 = 0x0260,
|
||||
.has_vop_sel = true,
|
||||
.probe = rk3288_lvds_probe,
|
||||
.helper_funcs = &rk3288_lvds_encoder_helper_funcs,
|
||||
};
|
||||
|
||||
static const struct rockchip_lvds_soc_data px30_lvds_data = {
|
||||
.probe = px30_lvds_probe,
|
||||
.helper_funcs = &px30_lvds_encoder_helper_funcs,
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_lvds_dt_ids[] = {
|
||||
@ -327,6 +528,10 @@ static const struct of_device_id rockchip_lvds_dt_ids[] = {
|
||||
.compatible = "rockchip,rk3288-lvds",
|
||||
.data = &rk3288_lvds_data
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,px30-lvds",
|
||||
.data = &px30_lvds_data
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rockchip_lvds_dt_ids);
|
||||
@ -378,7 +583,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
||||
/* default set it as output rgb */
|
||||
lvds->output = DISPLAY_OUTPUT_RGB;
|
||||
else
|
||||
lvds->output = lvds_name_to_output(name);
|
||||
lvds->output = rockchip_lvds_name_to_output(name);
|
||||
|
||||
if (lvds->output < 0) {
|
||||
DRM_DEV_ERROR(dev, "invalid output type [%s]\n", name);
|
||||
@ -390,7 +595,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
||||
/* default set it as format vesa 18 */
|
||||
lvds->format = LVDS_VESA_18;
|
||||
else
|
||||
lvds->format = lvds_name_to_format(name);
|
||||
lvds->format = rockchip_lvds_name_to_format(name);
|
||||
|
||||
if (lvds->format < 0) {
|
||||
DRM_DEV_ERROR(dev, "invalid data-mapping format [%s]\n", name);
|
||||
@ -410,7 +615,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
||||
goto err_put_remote;
|
||||
}
|
||||
|
||||
drm_encoder_helper_add(encoder, &rockchip_lvds_encoder_helper_funcs);
|
||||
drm_encoder_helper_add(encoder, lvds->soc_data->helper_funcs);
|
||||
|
||||
if (lvds->panel) {
|
||||
connector = &lvds->connector;
|
||||
@ -471,8 +676,10 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct rockchip_lvds *lvds = dev_get_drvdata(dev);
|
||||
const struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
|
||||
rockchip_lvds_encoder_disable(&lvds->encoder);
|
||||
encoder_funcs = lvds->soc_data->helper_funcs;
|
||||
encoder_funcs->disable(&lvds->encoder);
|
||||
if (lvds->panel)
|
||||
drm_panel_detach(lvds->panel);
|
||||
pm_runtime_disable(dev);
|
||||
@ -490,7 +697,6 @@ static int rockchip_lvds_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rockchip_lvds *lvds;
|
||||
const struct of_device_id *match;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
if (!dev->of_node)
|
||||
@ -506,37 +712,6 @@ static int rockchip_lvds_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
lvds->soc_data = match->data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
lvds->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(lvds->regs))
|
||||
return PTR_ERR(lvds->regs);
|
||||
|
||||
lvds->pclk = devm_clk_get(&pdev->dev, "pclk_lvds");
|
||||
if (IS_ERR(lvds->pclk)) {
|
||||
DRM_DEV_ERROR(dev, "could not get pclk_lvds\n");
|
||||
return PTR_ERR(lvds->pclk);
|
||||
}
|
||||
|
||||
lvds->pins = devm_kzalloc(lvds->dev, sizeof(*lvds->pins),
|
||||
GFP_KERNEL);
|
||||
if (!lvds->pins)
|
||||
return -ENOMEM;
|
||||
|
||||
lvds->pins->p = devm_pinctrl_get(lvds->dev);
|
||||
if (IS_ERR(lvds->pins->p)) {
|
||||
DRM_DEV_ERROR(dev, "no pinctrl handle\n");
|
||||
devm_kfree(lvds->dev, lvds->pins);
|
||||
lvds->pins = NULL;
|
||||
} else {
|
||||
lvds->pins->default_state =
|
||||
pinctrl_lookup_state(lvds->pins->p, "lcdc");
|
||||
if (IS_ERR(lvds->pins->default_state)) {
|
||||
DRM_DEV_ERROR(dev, "no default pinctrl state\n");
|
||||
devm_kfree(lvds->dev, lvds->pins);
|
||||
lvds->pins = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"rockchip,grf");
|
||||
if (IS_ERR(lvds->grf)) {
|
||||
@ -544,13 +719,14 @@ static int rockchip_lvds_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(lvds->grf);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, lvds);
|
||||
|
||||
ret = clk_prepare(lvds->pclk);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dev, "failed to prepare pclk_lvds\n");
|
||||
ret = lvds->soc_data->probe(pdev, lvds);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev, "Platform initialization failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, lvds);
|
||||
|
||||
ret = component_add(&pdev->dev, &rockchip_lvds_component_ops);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dev, "failed to add component\n");
|
||||
|
@ -70,7 +70,10 @@
|
||||
#define RK3288_LVDS_CFG_REG21 0x84
|
||||
#define RK3288_LVDS_CFG_REG21_TX_ENABLE 0x92
|
||||
#define RK3288_LVDS_CFG_REG21_TX_DISABLE 0x00
|
||||
#define RK3288_LVDS_CH1_OFFSET 0x100
|
||||
#define RK3288_LVDS_CH1_OFFSET 0x100
|
||||
|
||||
#define RK3288_LVDS_GRF_SOC_CON6 0x025C
|
||||
#define RK3288_LVDS_GRF_SOC_CON7 0x0260
|
||||
|
||||
/* fbdiv value is split over 2 registers, with bit8 in reg2 */
|
||||
#define RK3288_LVDS_PLL_FBDIV_REG2(_fbd) \
|
||||
@ -103,4 +106,18 @@
|
||||
#define LVDS_VESA_18 2
|
||||
#define LVDS_JEIDA_18 3
|
||||
|
||||
#define HIWORD_UPDATE(v, h, l) ((GENMASK(h, l) << 16) | ((v) << (l)))
|
||||
|
||||
#define PX30_LVDS_GRF_PD_VO_CON0 0x434
|
||||
#define PX30_LVDS_TIE_CLKS(val) HIWORD_UPDATE(val, 8, 8)
|
||||
#define PX30_LVDS_INVERT_CLKS(val) HIWORD_UPDATE(val, 9, 9)
|
||||
#define PX30_LVDS_INVERT_DCLK(val) HIWORD_UPDATE(val, 5, 5)
|
||||
|
||||
#define PX30_LVDS_GRF_PD_VO_CON1 0x438
|
||||
#define PX30_LVDS_FORMAT(val) HIWORD_UPDATE(val, 14, 13)
|
||||
#define PX30_LVDS_MODE_EN(val) HIWORD_UPDATE(val, 12, 12)
|
||||
#define PX30_LVDS_MSBSEL(val) HIWORD_UPDATE(val, 11, 11)
|
||||
#define PX30_LVDS_P2S_EN(val) HIWORD_UPDATE(val, 6, 6)
|
||||
#define PX30_LVDS_VOP_SEL(val) HIWORD_UPDATE(val, 1, 1)
|
||||
|
||||
#endif /* _ROCKCHIP_LVDS_ */
|
||||
|
@ -405,20 +405,8 @@ static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
|
||||
|
||||
int __init mc68x328fb_setup(char *options)
|
||||
{
|
||||
#if 0
|
||||
char *this_opt;
|
||||
#endif
|
||||
|
||||
if (!options || !*options)
|
||||
return 1;
|
||||
#if 0
|
||||
while ((this_opt = strsep(&options, ",")) != NULL) {
|
||||
if (!*this_opt)
|
||||
continue;
|
||||
if (!strncmp(this_opt, "disable", 7))
|
||||
mc68x328fb_enable = 0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -536,6 +536,13 @@ static int __init fb_console_setup(char *this_opt)
|
||||
fb_center_logo = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(options, "logo-count:", 11)) {
|
||||
options += 11;
|
||||
if (*options)
|
||||
fb_logo_count = simple_strtol(options, &options, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -54,7 +54,8 @@ int num_registered_fb __read_mostly;
|
||||
EXPORT_SYMBOL(num_registered_fb);
|
||||
|
||||
bool fb_center_logo __read_mostly;
|
||||
EXPORT_SYMBOL(fb_center_logo);
|
||||
|
||||
int fb_logo_count __read_mostly = -1;
|
||||
|
||||
static struct fb_info *get_fb_info(unsigned int idx)
|
||||
{
|
||||
@ -620,7 +621,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
|
||||
memset(&fb_logo, 0, sizeof(struct logo_data));
|
||||
|
||||
if (info->flags & FBINFO_MISC_TILEBLITTING ||
|
||||
info->fbops->owner)
|
||||
info->fbops->owner || !fb_logo_count)
|
||||
return 0;
|
||||
|
||||
if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
|
||||
@ -686,10 +687,14 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
|
||||
|
||||
int fb_show_logo(struct fb_info *info, int rotate)
|
||||
{
|
||||
unsigned int count;
|
||||
int y;
|
||||
|
||||
y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
|
||||
num_online_cpus());
|
||||
if (!fb_logo_count)
|
||||
return 0;
|
||||
|
||||
count = fb_logo_count < 0 ? num_online_cpus() : fb_logo_count;
|
||||
y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count);
|
||||
y = fb_show_extra_logos(info, y, rotate);
|
||||
|
||||
return y;
|
||||
|
@ -1287,6 +1287,7 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
dev_warn(info->dev,
|
||||
"MFB_SET_PIXFMT value of 0x%08x is deprecated.\n",
|
||||
MFB_SET_PIXFMT_OLD);
|
||||
/* fall through */
|
||||
case MFB_SET_PIXFMT:
|
||||
if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
|
||||
return -EFAULT;
|
||||
@ -1296,6 +1297,7 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
dev_warn(info->dev,
|
||||
"MFB_GET_PIXFMT value of 0x%08x is deprecated.\n",
|
||||
MFB_GET_PIXFMT_OLD);
|
||||
/* fall through */
|
||||
case MFB_GET_PIXFMT:
|
||||
pix_fmt = ad->pix_fmt;
|
||||
if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
|
||||
|
@ -673,7 +673,10 @@ static int parse_pins5(struct matrox_fb_info *minfo,
|
||||
if (bd->pins[115] & 4) {
|
||||
minfo->values.reg.mctlwtst_core = minfo->values.reg.mctlwtst;
|
||||
} else {
|
||||
u_int32_t wtst_xlat[] = { 0, 1, 5, 6, 7, 5, 2, 3 };
|
||||
static const u8 wtst_xlat[] = {
|
||||
0, 1, 5, 6, 7, 5, 2, 3
|
||||
};
|
||||
|
||||
minfo->values.reg.mctlwtst_core = (minfo->values.reg.mctlwtst & ~7) |
|
||||
wtst_xlat[minfo->values.reg.mctlwtst & 7];
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
menuconfig MMP_DISP
|
||||
tristate "Marvell MMP Display Subsystem support"
|
||||
depends on CPU_PXA910 || CPU_MMP2
|
||||
depends on CPU_PXA910 || CPU_MMP2 || COMPILE_TEST
|
||||
help
|
||||
Marvell Display Subsystem support.
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
if MMP_DISP
|
||||
|
||||
config MMP_FB
|
||||
tristate "fb driver for Marvell MMP Display Subsystem"
|
||||
depends on FB
|
||||
@ -10,5 +8,3 @@ config MMP_FB
|
||||
default y
|
||||
help
|
||||
fb driver for Marvell MMP Display Subsystem
|
||||
|
||||
endif
|
||||
|
@ -522,7 +522,7 @@ static int fb_info_setup(struct fb_info *info,
|
||||
info->var.bits_per_pixel / 8;
|
||||
info->fbops = &mmpfb_ops;
|
||||
info->pseudo_palette = fbi->pseudo_palette;
|
||||
info->screen_base = fbi->fb_start;
|
||||
info->screen_buffer = fbi->fb_start;
|
||||
info->screen_size = fbi->fb_size;
|
||||
|
||||
/* For FB framework: Allocate color map and Register framebuffer*/
|
||||
|
@ -1,9 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
if MMP_DISP
|
||||
|
||||
config MMP_DISP_CONTROLLER
|
||||
bool "mmp display controller hw support"
|
||||
depends on CPU_PXA910 || CPU_MMP2
|
||||
depends on HAVE_CLK && HAS_IOMEM
|
||||
depends on CPU_PXA910 || CPU_MMP2 || COMPILE_TEST
|
||||
help
|
||||
Marvell MMP display hw controller support
|
||||
this controller is used on Marvell PXA910 and
|
||||
@ -16,5 +15,3 @@ config MMP_DISP_SPI
|
||||
help
|
||||
Marvell MMP display hw controller spi port support
|
||||
will register as a spi master for panel usage
|
||||
|
||||
endif
|
||||
|
@ -136,19 +136,26 @@ static void overlay_set_win(struct mmp_overlay *overlay, struct mmp_win *win)
|
||||
mutex_lock(&overlay->access_ok);
|
||||
|
||||
if (overlay_is_vid(overlay)) {
|
||||
writel_relaxed(win->pitch[0], ®s->v_pitch_yc);
|
||||
writel_relaxed(win->pitch[2] << 16 |
|
||||
win->pitch[1], ®s->v_pitch_uv);
|
||||
writel_relaxed(win->pitch[0],
|
||||
(void __iomem *)®s->v_pitch_yc);
|
||||
writel_relaxed(win->pitch[2] << 16 | win->pitch[1],
|
||||
(void __iomem *)®s->v_pitch_uv);
|
||||
|
||||
writel_relaxed((win->ysrc << 16) | win->xsrc, ®s->v_size);
|
||||
writel_relaxed((win->ydst << 16) | win->xdst, ®s->v_size_z);
|
||||
writel_relaxed(win->ypos << 16 | win->xpos, ®s->v_start);
|
||||
writel_relaxed((win->ysrc << 16) | win->xsrc,
|
||||
(void __iomem *)®s->v_size);
|
||||
writel_relaxed((win->ydst << 16) | win->xdst,
|
||||
(void __iomem *)®s->v_size_z);
|
||||
writel_relaxed(win->ypos << 16 | win->xpos,
|
||||
(void __iomem *)®s->v_start);
|
||||
} else {
|
||||
writel_relaxed(win->pitch[0], ®s->g_pitch);
|
||||
writel_relaxed(win->pitch[0], (void __iomem *)®s->g_pitch);
|
||||
|
||||
writel_relaxed((win->ysrc << 16) | win->xsrc, ®s->g_size);
|
||||
writel_relaxed((win->ydst << 16) | win->xdst, ®s->g_size_z);
|
||||
writel_relaxed(win->ypos << 16 | win->xpos, ®s->g_start);
|
||||
writel_relaxed((win->ysrc << 16) | win->xsrc,
|
||||
(void __iomem *)®s->g_size);
|
||||
writel_relaxed((win->ydst << 16) | win->xdst,
|
||||
(void __iomem *)®s->g_size_z);
|
||||
writel_relaxed(win->ypos << 16 | win->xpos,
|
||||
(void __iomem *)®s->g_start);
|
||||
}
|
||||
|
||||
dmafetch_set_fmt(overlay);
|
||||
@ -233,11 +240,11 @@ static int overlay_set_addr(struct mmp_overlay *overlay, struct mmp_addr *addr)
|
||||
memcpy(&overlay->addr, addr, sizeof(struct mmp_addr));
|
||||
|
||||
if (overlay_is_vid(overlay)) {
|
||||
writel_relaxed(addr->phys[0], ®s->v_y0);
|
||||
writel_relaxed(addr->phys[1], ®s->v_u0);
|
||||
writel_relaxed(addr->phys[2], ®s->v_v0);
|
||||
writel_relaxed(addr->phys[0], (void __iomem *)®s->v_y0);
|
||||
writel_relaxed(addr->phys[1], (void __iomem *)®s->v_u0);
|
||||
writel_relaxed(addr->phys[2], (void __iomem *)®s->v_v0);
|
||||
} else
|
||||
writel_relaxed(addr->phys[0], ®s->g_0);
|
||||
writel_relaxed(addr->phys[0], (void __iomem *)®s->g_0);
|
||||
|
||||
return overlay->addr.phys[0];
|
||||
}
|
||||
@ -268,16 +275,18 @@ static void path_set_mode(struct mmp_path *path, struct mmp_mode *mode)
|
||||
tmp |= dsi_rbswap & CFG_INTFRBSWAP_MASK;
|
||||
writel_relaxed(tmp, ctrl_regs(path) + intf_rbswap_ctrl(path->id));
|
||||
|
||||
writel_relaxed((mode->yres << 16) | mode->xres, ®s->screen_active);
|
||||
writel_relaxed((mode->yres << 16) | mode->xres,
|
||||
(void __iomem *)®s->screen_active);
|
||||
writel_relaxed((mode->left_margin << 16) | mode->right_margin,
|
||||
®s->screen_h_porch);
|
||||
(void __iomem *)®s->screen_h_porch);
|
||||
writel_relaxed((mode->upper_margin << 16) | mode->lower_margin,
|
||||
®s->screen_v_porch);
|
||||
(void __iomem *)®s->screen_v_porch);
|
||||
total_x = mode->xres + mode->left_margin + mode->right_margin +
|
||||
mode->hsync_len;
|
||||
total_y = mode->yres + mode->upper_margin + mode->lower_margin +
|
||||
mode->vsync_len;
|
||||
writel_relaxed((total_y << 16) | total_x, ®s->screen_size);
|
||||
writel_relaxed((total_y << 16) | total_x,
|
||||
(void __iomem *)®s->screen_size);
|
||||
|
||||
/* vsync ctrl */
|
||||
if (path->output_type == PATH_OUT_DSI)
|
||||
@ -285,7 +294,7 @@ static void path_set_mode(struct mmp_path *path, struct mmp_mode *mode)
|
||||
else
|
||||
vsync_ctrl = ((mode->xres + mode->right_margin) << 16)
|
||||
| (mode->xres + mode->right_margin);
|
||||
writel_relaxed(vsync_ctrl, ®s->vsync_ctrl);
|
||||
writel_relaxed(vsync_ctrl, (void __iomem *)®s->vsync_ctrl);
|
||||
|
||||
/* set pixclock div */
|
||||
sclk_src = clk_get_rate(path_to_ctrl(path)->clk);
|
||||
@ -366,9 +375,9 @@ static void path_set_default(struct mmp_path *path)
|
||||
writel_relaxed(dma_ctrl1, ctrl_regs(path) + dma_ctrl(1, path->id));
|
||||
|
||||
/* Configure default register values */
|
||||
writel_relaxed(0x00000000, ®s->blank_color);
|
||||
writel_relaxed(0x00000000, ®s->g_1);
|
||||
writel_relaxed(0x00000000, ®s->g_start);
|
||||
writel_relaxed(0x00000000, (void __iomem *)®s->blank_color);
|
||||
writel_relaxed(0x00000000, (void __iomem *)®s->g_1);
|
||||
writel_relaxed(0x00000000, (void __iomem *)®s->g_start);
|
||||
|
||||
/*
|
||||
* 1.enable multiple burst request in DMA AXI
|
||||
|
@ -1393,7 +1393,7 @@ struct mmphw_ctrl {
|
||||
/* platform related, get from config */
|
||||
const char *name;
|
||||
int irq;
|
||||
void *reg_base;
|
||||
void __iomem *reg_base;
|
||||
struct clk *clk;
|
||||
|
||||
/* sys info */
|
||||
@ -1429,7 +1429,7 @@ static inline struct mmphw_ctrl *overlay_to_ctrl(struct mmp_overlay *overlay)
|
||||
return path_to_ctrl(overlay->path);
|
||||
}
|
||||
|
||||
static inline void *ctrl_regs(struct mmp_path *path)
|
||||
static inline void __iomem *ctrl_regs(struct mmp_path *path)
|
||||
{
|
||||
return path_to_ctrl(path)->reg_base;
|
||||
}
|
||||
@ -1438,11 +1438,11 @@ static inline void *ctrl_regs(struct mmp_path *path)
|
||||
static inline struct lcd_regs *path_regs(struct mmp_path *path)
|
||||
{
|
||||
if (path->id == PATH_PN)
|
||||
return (struct lcd_regs *)(ctrl_regs(path) + 0xc0);
|
||||
return (struct lcd_regs __force *)(ctrl_regs(path) + 0xc0);
|
||||
else if (path->id == PATH_TV)
|
||||
return (struct lcd_regs *)ctrl_regs(path);
|
||||
return (struct lcd_regs __force *)ctrl_regs(path);
|
||||
else if (path->id == PATH_P2)
|
||||
return (struct lcd_regs *)(ctrl_regs(path) + 0x200);
|
||||
return (struct lcd_regs __force *)(ctrl_regs(path) + 0x200);
|
||||
else {
|
||||
dev_err(path->dev, "path id %d invalid\n", path->id);
|
||||
BUG_ON(1);
|
||||
|
@ -31,7 +31,7 @@ static inline int lcd_spi_write(struct spi_device *spi, u32 data)
|
||||
{
|
||||
int timeout = 100000, isr, ret = 0;
|
||||
u32 tmp;
|
||||
void *reg_base =
|
||||
void __iomem *reg_base = (void __iomem *)
|
||||
*(void **)spi_master_get_devdata(spi->master);
|
||||
|
||||
/* clear ISR */
|
||||
@ -80,7 +80,7 @@ static inline int lcd_spi_write(struct spi_device *spi, u32 data)
|
||||
|
||||
static int lcd_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
void *reg_base =
|
||||
void __iomem *reg_base = (void __iomem *)
|
||||
*(void **)spi_master_get_devdata(spi->master);
|
||||
u32 tmp;
|
||||
|
||||
@ -146,7 +146,7 @@ int lcd_spi_register(struct mmphw_ctrl *ctrl)
|
||||
return -ENOMEM;
|
||||
}
|
||||
p_regbase = spi_master_get_devdata(master);
|
||||
*p_regbase = ctrl->reg_base;
|
||||
*p_regbase = (void __force *)ctrl->reg_base;
|
||||
|
||||
/* set bus num to 5 to avoid conflict with other spi hosts */
|
||||
master->bus_num = 5;
|
||||
|
@ -297,7 +297,6 @@ static int ocfb_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ocfb_dev *fbdev;
|
||||
struct resource *res;
|
||||
int fbsize;
|
||||
|
||||
fbdev = devm_kzalloc(&pdev->dev, sizeof(*fbdev), GFP_KERNEL);
|
||||
@ -319,13 +318,7 @@ static int ocfb_probe(struct platform_device *pdev)
|
||||
ocfb_init_var(fbdev);
|
||||
ocfb_init_fix(fbdev);
|
||||
|
||||
/* Request I/O resource */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "I/O resource request failed\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
fbdev->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
fbdev->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(fbdev->regs))
|
||||
return PTR_ERR(fbdev->regs);
|
||||
|
||||
|
@ -1635,7 +1635,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
|
||||
{
|
||||
int scale_x = out_width != orig_width;
|
||||
int scale_y = out_height != orig_height;
|
||||
bool chroma_upscale = plane != OMAP_DSS_WB ? true : false;
|
||||
bool chroma_upscale = plane != OMAP_DSS_WB;
|
||||
|
||||
if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
|
||||
return;
|
||||
@ -3100,9 +3100,9 @@ static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
|
||||
unsigned long pclk)
|
||||
{
|
||||
if (dss_mgr_is_lcd(channel))
|
||||
return pclk <= dispc.feat->max_lcd_pclk ? true : false;
|
||||
return pclk <= dispc.feat->max_lcd_pclk;
|
||||
else
|
||||
return pclk <= dispc.feat->max_tv_pclk ? true : false;
|
||||
return pclk <= dispc.feat->max_tv_pclk;
|
||||
}
|
||||
|
||||
bool dispc_mgr_timings_ok(enum omap_channel channel,
|
||||
|
@ -339,9 +339,7 @@ static int __init vrfb_probe(struct platform_device *pdev)
|
||||
int i;
|
||||
|
||||
/* first resource is the register res, the rest are vrfb contexts */
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
vrfb_base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
vrfb_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(vrfb_base))
|
||||
return PTR_ERR(vrfb_base);
|
||||
|
||||
|
@ -766,8 +766,8 @@ failed_free_cmap:
|
||||
failed_free_clk:
|
||||
clk_disable_unprepare(fbi->clk);
|
||||
failed_free_fbmem:
|
||||
dma_free_coherent(fbi->dev, info->fix.smem_len,
|
||||
info->screen_base, fbi->fb_start_dma);
|
||||
dma_free_wc(fbi->dev, info->fix.smem_len,
|
||||
info->screen_base, fbi->fb_start_dma);
|
||||
failed_free_info:
|
||||
kfree(info);
|
||||
|
||||
@ -801,7 +801,7 @@ static int pxa168fb_remove(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
||||
dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
|
||||
dma_free_wc(fbi->dev, info->fix.smem_len,
|
||||
info->screen_base, info->fix.smem_start);
|
||||
|
||||
clk_disable_unprepare(fbi->clk);
|
||||
|
@ -2237,7 +2237,6 @@ static int pxafb_probe(struct platform_device *dev)
|
||||
{
|
||||
struct pxafb_info *fbi;
|
||||
struct pxafb_mach_info *inf, *pdata;
|
||||
struct resource *r;
|
||||
int i, irq, ret;
|
||||
|
||||
dev_dbg(&dev->dev, "pxafb_probe\n");
|
||||
@ -2303,14 +2302,7 @@ static int pxafb_probe(struct platform_device *dev)
|
||||
fbi->lcd_supply = NULL;
|
||||
}
|
||||
|
||||
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (r == NULL) {
|
||||
dev_err(&dev->dev, "no I/O memory resource defined\n");
|
||||
ret = -ENODEV;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fbi->mmio_base = devm_ioremap_resource(&dev->dev, r);
|
||||
fbi->mmio_base = devm_platform_ioremap_resource(dev, 0);
|
||||
if (IS_ERR(fbi->mmio_base)) {
|
||||
dev_err(&dev->dev, "failed to get I/O memory\n");
|
||||
ret = -EBUSY;
|
||||
|
@ -1411,8 +1411,7 @@ static int s3c_fb_probe(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_enable(sfb->dev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
sfb->regs = devm_ioremap_resource(dev, res);
|
||||
sfb->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(sfb->regs)) {
|
||||
ret = PTR_ERR(sfb->regs);
|
||||
goto err_lcd_clk;
|
||||
|
@ -1143,7 +1143,6 @@ static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)
|
||||
static int sa1100fb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sa1100fb_info *fbi;
|
||||
struct resource *res;
|
||||
int ret, irq;
|
||||
|
||||
if (!dev_get_platdata(&pdev->dev)) {
|
||||
@ -1159,8 +1158,7 @@ static int sa1100fb_probe(struct platform_device *pdev)
|
||||
if (!fbi)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
fbi->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
fbi->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(fbi->base))
|
||||
return PTR_ERR(fbi->base);
|
||||
|
||||
|
@ -669,6 +669,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
|
||||
return plane->state;
|
||||
}
|
||||
|
||||
int __must_check
|
||||
drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
|
||||
struct drm_encoder *encoder);
|
||||
int __must_check
|
||||
drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
|
||||
struct drm_crtc *crtc);
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_mode_object.h>
|
||||
#include <drm/drm_modes.h>
|
||||
@ -33,6 +35,65 @@ struct drm_bridge;
|
||||
struct drm_bridge_timings;
|
||||
struct drm_panel;
|
||||
|
||||
/**
|
||||
* struct drm_bus_cfg - bus configuration
|
||||
*
|
||||
* This structure stores the configuration of a physical bus between two
|
||||
* components in an output pipeline, usually between two bridges, an encoder
|
||||
* and a bridge, or a bridge and a connector.
|
||||
*
|
||||
* The bus configuration is stored in &drm_bridge_state separately for the
|
||||
* input and output buses, as seen from the point of view of each bridge. The
|
||||
* bus configuration of a bridge output is usually identical to the
|
||||
* configuration of the next bridge's input, but may differ if the signals are
|
||||
* modified between the two bridges, for instance by an inverter on the board.
|
||||
* The input and output configurations of a bridge may differ if the bridge
|
||||
* modifies the signals internally, for instance by performing format
|
||||
* conversion, or modifying signals polarities.
|
||||
*/
|
||||
struct drm_bus_cfg {
|
||||
/**
|
||||
* @format: format used on this bus (one of the MEDIA_BUS_FMT_* format)
|
||||
*
|
||||
* This field should not be directly modified by drivers
|
||||
* (&drm_atomic_bridge_chain_select_bus_fmts() takes care of the bus
|
||||
* format negotiation).
|
||||
*/
|
||||
u32 format;
|
||||
|
||||
/**
|
||||
* @flags: DRM_BUS_* flags used on this bus
|
||||
*/
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_bridge_state - Atomic bridge state object
|
||||
* @base: inherit from &drm_private_state
|
||||
* @bridge: the bridge this state refers to
|
||||
*/
|
||||
struct drm_bridge_state {
|
||||
struct drm_private_state base;
|
||||
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
/**
|
||||
* @input_bus_cfg: input bus configuration
|
||||
*/
|
||||
struct drm_bus_cfg input_bus_cfg;
|
||||
|
||||
/**
|
||||
* @output_bus_cfg: input bus configuration
|
||||
*/
|
||||
struct drm_bus_cfg output_bus_cfg;
|
||||
};
|
||||
|
||||
static inline struct drm_bridge_state *
|
||||
drm_priv_to_bridge_state(struct drm_private_state *priv)
|
||||
{
|
||||
return container_of(priv, struct drm_bridge_state, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct drm_bridge_funcs - drm_bridge control functions
|
||||
*/
|
||||
@ -109,7 +170,9 @@ struct drm_bridge_funcs {
|
||||
* this function passes all other callbacks must succeed for this
|
||||
* configuration.
|
||||
*
|
||||
* The @mode_fixup callback is optional.
|
||||
* The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup()
|
||||
* is not called when &drm_bridge_funcs.atomic_check() is implemented,
|
||||
* so only one of them should be provided.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
@ -263,7 +326,7 @@ struct drm_bridge_funcs {
|
||||
* The @atomic_pre_enable callback is optional.
|
||||
*/
|
||||
void (*atomic_pre_enable)(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state);
|
||||
struct drm_bridge_state *old_bridge_state);
|
||||
|
||||
/**
|
||||
* @atomic_enable:
|
||||
@ -288,7 +351,7 @@ struct drm_bridge_funcs {
|
||||
* The @atomic_enable callback is optional.
|
||||
*/
|
||||
void (*atomic_enable)(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state);
|
||||
struct drm_bridge_state *old_bridge_state);
|
||||
/**
|
||||
* @atomic_disable:
|
||||
*
|
||||
@ -311,7 +374,7 @@ struct drm_bridge_funcs {
|
||||
* The @atomic_disable callback is optional.
|
||||
*/
|
||||
void (*atomic_disable)(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state);
|
||||
struct drm_bridge_state *old_bridge_state);
|
||||
|
||||
/**
|
||||
* @atomic_post_disable:
|
||||
@ -337,7 +400,146 @@ struct drm_bridge_funcs {
|
||||
* The @atomic_post_disable callback is optional.
|
||||
*/
|
||||
void (*atomic_post_disable)(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state);
|
||||
struct drm_bridge_state *old_bridge_state);
|
||||
|
||||
/**
|
||||
* @atomic_duplicate_state:
|
||||
*
|
||||
* Duplicate the current bridge state object (which is guaranteed to be
|
||||
* non-NULL).
|
||||
*
|
||||
* The atomic_duplicate_state() is optional. When not implemented the
|
||||
* core allocates a drm_bridge_state object and calls
|
||||
* &__drm_atomic_helper_bridge_duplicate_state() to initialize it.
|
||||
*
|
||||
* RETURNS:
|
||||
* A valid drm_bridge_state object or NULL if the allocation fails.
|
||||
*/
|
||||
struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge);
|
||||
|
||||
/**
|
||||
* @atomic_destroy_state:
|
||||
*
|
||||
* Destroy a bridge state object previously allocated by
|
||||
* &drm_bridge_funcs.atomic_duplicate_state().
|
||||
*
|
||||
* The atomic_destroy_state hook is optional. When not implemented the
|
||||
* core calls kfree() on the state.
|
||||
*/
|
||||
void (*atomic_destroy_state)(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *state);
|
||||
|
||||
/**
|
||||
* @atomic_get_output_bus_fmts:
|
||||
*
|
||||
* Return the supported bus formats on the output end of a bridge.
|
||||
* The returned array must be allocated with kmalloc() and will be
|
||||
* freed by the caller. If the allocation fails, NULL should be
|
||||
* returned. num_output_fmts must be set to the returned array size.
|
||||
* Formats listed in the returned array should be listed in decreasing
|
||||
* preference order (the core will try all formats until it finds one
|
||||
* that works).
|
||||
*
|
||||
* This method is only called on the last element of the bridge chain
|
||||
* as part of the bus format negotiation process that happens in
|
||||
* &drm_atomic_bridge_chain_select_bus_fmts().
|
||||
* This method is optional. When not implemented, the core will
|
||||
* fall back to &drm_connector.display_info.bus_formats[0] if
|
||||
* &drm_connector.display_info.num_bus_formats > 0,
|
||||
* or to MEDIA_BUS_FMT_FIXED otherwise.
|
||||
*/
|
||||
u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *bridge_state,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state,
|
||||
unsigned int *num_output_fmts);
|
||||
|
||||
/**
|
||||
* @atomic_get_input_bus_fmts:
|
||||
*
|
||||
* Return the supported bus formats on the input end of a bridge for
|
||||
* a specific output bus format.
|
||||
*
|
||||
* The returned array must be allocated with kmalloc() and will be
|
||||
* freed by the caller. If the allocation fails, NULL should be
|
||||
* returned. num_output_fmts must be set to the returned array size.
|
||||
* Formats listed in the returned array should be listed in decreasing
|
||||
* preference order (the core will try all formats until it finds one
|
||||
* that works). When the format is not supported NULL should be
|
||||
* returned and *num_output_fmts should be set to 0.
|
||||
*
|
||||
* This method is called on all elements of the bridge chain as part of
|
||||
* the bus format negotiation process that happens in
|
||||
* &drm_atomic_bridge_chain_select_bus_fmts().
|
||||
* This method is optional. When not implemented, the core will bypass
|
||||
* bus format negotiation on this element of the bridge without
|
||||
* failing, and the previous element in the chain will be passed
|
||||
* MEDIA_BUS_FMT_FIXED as its output bus format.
|
||||
*
|
||||
* Bridge drivers that need to support being linked to bridges that are
|
||||
* not supporting bus format negotiation should handle the
|
||||
* output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a
|
||||
* sensible default value or extracting this information from somewhere
|
||||
* else (FW property, &drm_display_mode, &drm_display_info, ...)
|
||||
*
|
||||
* Note: Even if input format selection on the first bridge has no
|
||||
* impact on the negotiation process (bus format negotiation stops once
|
||||
* we reach the first element of the chain), drivers are expected to
|
||||
* return accurate input formats as the input format may be used to
|
||||
* configure the CRTC output appropriately.
|
||||
*/
|
||||
u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *bridge_state,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state,
|
||||
u32 output_fmt,
|
||||
unsigned int *num_input_fmts);
|
||||
|
||||
/**
|
||||
* @atomic_check:
|
||||
*
|
||||
* This method is responsible for checking bridge state correctness.
|
||||
* It can also check the state of the surrounding components in chain
|
||||
* to make sure the whole pipeline can work properly.
|
||||
*
|
||||
* &drm_bridge_funcs.atomic_check() hooks are called in reverse
|
||||
* order (from the last to the first bridge).
|
||||
*
|
||||
* This method is optional. &drm_bridge_funcs.mode_fixup() is not
|
||||
* called when &drm_bridge_funcs.atomic_check() is implemented, so only
|
||||
* one of them should be provided.
|
||||
*
|
||||
* If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or
|
||||
* &drm_bridge_state.output_bus_cfg.flags it should should happen in
|
||||
* this function. By default the &drm_bridge_state.output_bus_cfg.flags
|
||||
* field is set to the next bridge
|
||||
* &drm_bridge_state.input_bus_cfg.flags value or
|
||||
* &drm_connector.display_info.bus_flags if the bridge is the last
|
||||
* element in the chain.
|
||||
*
|
||||
* RETURNS:
|
||||
* zero if the check passed, a negative error code otherwise.
|
||||
*/
|
||||
int (*atomic_check)(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *bridge_state,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state);
|
||||
|
||||
/**
|
||||
* @atomic_reset:
|
||||
*
|
||||
* Reset the bridge to a predefined state (or retrieve its current
|
||||
* state) and return a &drm_bridge_state object matching this state.
|
||||
* This function is called at attach time.
|
||||
*
|
||||
* The atomic_reset hook is optional. When not implemented the core
|
||||
* allocates a new state and calls &__drm_atomic_helper_bridge_reset().
|
||||
*
|
||||
* RETURNS:
|
||||
* A valid drm_bridge_state object in case of success, an ERR_PTR()
|
||||
* giving the reason of the failure otherwise.
|
||||
*/
|
||||
struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -380,6 +582,8 @@ struct drm_bridge_timings {
|
||||
* struct drm_bridge - central DRM bridge control structure
|
||||
*/
|
||||
struct drm_bridge {
|
||||
/** @base: inherit from &drm_private_object */
|
||||
struct drm_private_obj base;
|
||||
/** @dev: DRM device this bridge belongs to */
|
||||
struct drm_device *dev;
|
||||
/** @encoder: encoder to which this bridge is connected */
|
||||
@ -404,6 +608,12 @@ struct drm_bridge {
|
||||
void *driver_private;
|
||||
};
|
||||
|
||||
static inline struct drm_bridge *
|
||||
drm_priv_to_bridge(struct drm_private_obj *priv)
|
||||
{
|
||||
return container_of(priv, struct drm_bridge, base);
|
||||
}
|
||||
|
||||
void drm_bridge_add(struct drm_bridge *bridge);
|
||||
void drm_bridge_remove(struct drm_bridge *bridge);
|
||||
struct drm_bridge *of_drm_find_bridge(struct device_node *np);
|
||||
@ -482,6 +692,9 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
|
||||
void drm_bridge_chain_pre_enable(struct drm_bridge *bridge);
|
||||
void drm_bridge_chain_enable(struct drm_bridge *bridge);
|
||||
|
||||
int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state);
|
||||
void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state);
|
||||
void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
|
||||
@ -491,6 +704,58 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
|
||||
void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state);
|
||||
|
||||
u32 *
|
||||
drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *bridge_state,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state,
|
||||
u32 output_fmt,
|
||||
unsigned int *num_input_fmts);
|
||||
|
||||
void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *state);
|
||||
void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *new);
|
||||
|
||||
static inline struct drm_bridge_state *
|
||||
drm_atomic_get_bridge_state(struct drm_atomic_state *state,
|
||||
struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_private_state *obj_state;
|
||||
|
||||
obj_state = drm_atomic_get_private_obj_state(state, &bridge->base);
|
||||
if (IS_ERR(obj_state))
|
||||
return ERR_CAST(obj_state);
|
||||
|
||||
return drm_priv_to_bridge_state(obj_state);
|
||||
}
|
||||
|
||||
static inline struct drm_bridge_state *
|
||||
drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
|
||||
struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_private_state *obj_state;
|
||||
|
||||
obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base);
|
||||
if (!obj_state)
|
||||
return NULL;
|
||||
|
||||
return drm_priv_to_bridge_state(obj_state);
|
||||
}
|
||||
|
||||
static inline struct drm_bridge_state *
|
||||
drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
|
||||
struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_private_state *obj_state;
|
||||
|
||||
obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base);
|
||||
if (!obj_state)
|
||||
return NULL;
|
||||
|
||||
return drm_priv_to_bridge_state(obj_state);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_PANEL_BRIDGE
|
||||
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel);
|
||||
struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
|
||||
|
@ -93,10 +93,8 @@ static inline struct drm_gem_vram_object *drm_gem_vram_of_gem(
|
||||
}
|
||||
|
||||
struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev,
|
||||
struct ttm_bo_device *bdev,
|
||||
size_t size,
|
||||
unsigned long pg_align,
|
||||
bool interruptible);
|
||||
unsigned long pg_align);
|
||||
void drm_gem_vram_put(struct drm_gem_vram_object *gbo);
|
||||
u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo);
|
||||
s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo);
|
||||
@ -110,9 +108,8 @@ void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, void *vaddr);
|
||||
|
||||
int drm_gem_vram_fill_create_dumb(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
struct ttm_bo_device *bdev,
|
||||
unsigned long pg_align,
|
||||
bool interruptible,
|
||||
unsigned long pitch_align,
|
||||
struct drm_mode_create_dumb *args);
|
||||
|
||||
/*
|
||||
|
@ -625,6 +625,7 @@ extern int fb_new_modelist(struct fb_info *info);
|
||||
extern struct fb_info *registered_fb[FB_MAX];
|
||||
extern int num_registered_fb;
|
||||
extern bool fb_center_logo;
|
||||
extern int fb_logo_count;
|
||||
extern struct class *fb_class;
|
||||
|
||||
#define for_each_registered_fb(i) \
|
||||
|
Loading…
Reference in New Issue
Block a user