mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 09:13:55 +08:00
drm-misc-next for v5.18:
UAPI Changes: Cross-subsystem Changes: - Improve performance of some fbdev ops, in some cases up to 6x faster. Core Changes: - Some small DP fixes. - Find panels in subnodes of OF devices, and add of_get_drm_panel_display_mode to retrieve mode. - Add drm_object_property_get_default_value and use it for resetting zpos in plane state reset, removing the need for individual drivers to do it. - Same for color encoding and color range props. - Update panic handling todo doc. - Add todo that format conversion helpers should be sped up similarly to fbdev ops. Driver Changes: - Add panel orientation property to simpledrm for quirked panels. - Assorted small fixes to tiny/repaper, nouveau, stm, omap, ssd130x. - Add crc support to stm/ltdc. - Add MIPI DBI compatible SPI driver - Assorted small fixes to tiny panels and bridge drivers. - Add AST2600 support to aspeed. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmIgiiwACgkQ/lWMcqZw E8Nw8A//b9QTz/UJoeWo22IuDGJkM/LoUP1WCt9RvfY+caMJ1/Gk7k0KIjq9+Fo9 +DevKpAfpC8tCMAbzHvB/tRZ67h3ctxk7SLqPdT3blmblWF6zGxJbF8GYDMskvhn 1FTM9oczOkxhn5+CRw5D5ud0HcSxgqkIrUAzlcIli8wX9hSVwoqlAeRls+0VvORW Qp556Ji/x18VqhDU70r9JhevTszhvP7iCtg8I+JBezkKnyFiCx1Ca3Kwhz7NWq3k LDEmH0wTAr0cXYO7Of0w68Kii7uTo3OBv+tZ74/LFOpUdndjhltbvMB0qNNms/wr 3h2j0hvg7gcGRpfzJKXgjXKaevEnVxQH4NDUrLLElTOPydnick4Jqai4GYEpliek cPvE1IrPn9WHBQwIIdiiAcIarRmdka14+K8fJEXUWIIn5QQeOiUxTau3V5O8xCYB K8xphNM1YG6IkHs4NVtGmVHi/MC/0jR7PxAjsbwlcHD/GqMrvqoUru6NA6DowQii YbWjH5kmzy1K8s3SA9CJXsa42cVk4sh2WqbLhcBq+0lDotcMiu8cIyG8HO3VOAl5 Nuy1Lud8tS6BD/eotsw29HQsYHA/pmZpFlCm1ABkqfLFsqjwPz0DBHROsaB42g5C ma2K+ebRXdAFGAN0YCtGu/rlkGrSODWiagZSlaLWcu1izUoJSx4= =TVQP -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2022-03-03' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for v5.18: UAPI Changes: Cross-subsystem Changes: - Improve performance of some fbdev ops, in some cases up to 6x faster. Core Changes: - Some small DP fixes. - Find panels in subnodes of OF devices, and add of_get_drm_panel_display_mode to retrieve mode. - Add drm_object_property_get_default_value and use it for resetting zpos in plane state reset, removing the need for individual drivers to do it. - Same for color encoding and color range props. - Update panic handling todo doc. - Add todo that format conversion helpers should be sped up similarly to fbdev ops. Driver Changes: - Add panel orientation property to simpledrm for quirked panels. - Assorted small fixes to tiny/repaper, nouveau, stm, omap, ssd130x. - Add crc support to stm/ltdc. - Add MIPI DBI compatible SPI driver - Assorted small fixes to tiny panels and bridge drivers. - Add AST2600 support to aspeed. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/48fabd78-ade9-f80b-c724-13726c7be69e@linux.intel.com
This commit is contained in:
commit
c9e9ce0b6f
@ -0,0 +1,126 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/panel-mipi-dbi-spi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MIPI DBI SPI Panel
|
||||
|
||||
maintainers:
|
||||
- Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
description: |
|
||||
This binding is for display panels using a MIPI DBI compatible controller
|
||||
in SPI mode.
|
||||
|
||||
The MIPI Alliance Standard for Display Bus Interface defines the electrical
|
||||
and logical interfaces for display controllers historically used in mobile
|
||||
phones. The standard defines 4 display architecture types and this binding is
|
||||
for type 1 which has full frame memory. There are 3 interface types in the
|
||||
standard and type C is the serial interface.
|
||||
|
||||
The standard defines the following interface signals for type C:
|
||||
- Power:
|
||||
- Vdd: Power supply for display module
|
||||
- Vddi: Logic level supply for interface signals
|
||||
Combined into one in this binding called: power-supply
|
||||
- Interface:
|
||||
- CSx: Chip select
|
||||
- SCL: Serial clock
|
||||
- Dout: Serial out
|
||||
- Din: Serial in
|
||||
- SDA: Bidrectional in/out
|
||||
- D/CX: Data/command selection, high=data, low=command
|
||||
Called dc-gpios in this binding.
|
||||
- RESX: Reset when low
|
||||
Called reset-gpios in this binding.
|
||||
|
||||
The type C interface has 3 options:
|
||||
|
||||
- Option 1: 9-bit mode and D/CX as the 9th bit
|
||||
| Command | the next command or following data |
|
||||
|<0><D7><D6><D5><D4><D3><D2><D1><D0>|<D/CX><D7><D6><D5><D4><D3><D2><D1><D0>|
|
||||
|
||||
- Option 2: 16-bit mode and D/CX as a 9th bit
|
||||
| Command or data |
|
||||
|<X><X><X><X><X><X><X><D/CX><D7><D6><D5><D4><D3><D2><D1><D0>|
|
||||
|
||||
- Option 3: 8-bit mode and D/CX as a separate interface line
|
||||
| Command or data |
|
||||
|<D7><D6><D5><D4><D3><D2><D1><D0>|
|
||||
|
||||
The panel resolution is specified using the panel-timing node properties
|
||||
hactive (width) and vactive (height). The other mandatory panel-timing
|
||||
properties should be set to zero except clock-frequency which can be
|
||||
optionally set to inform about the actual pixel clock frequency.
|
||||
|
||||
If the panel is wired to the controller at an offset specify this using
|
||||
hback-porch (x-offset) and vback-porch (y-offset).
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- sainsmart18
|
||||
- const: panel-mipi-dbi-spi
|
||||
|
||||
write-only:
|
||||
type: boolean
|
||||
description:
|
||||
Controller is not readable (ie. Din (MISO on the SPI interface) is not
|
||||
wired up).
|
||||
|
||||
dc-gpios:
|
||||
maxItems: 1
|
||||
description: |
|
||||
Controller data/command selection (D/CX) in 4-line SPI mode.
|
||||
If not set, the controller is in 3-line SPI mode.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- panel-timing
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
display@0{
|
||||
compatible = "sainsmart18", "panel-mipi-dbi-spi";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <40000000>;
|
||||
|
||||
dc-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>;
|
||||
write-only;
|
||||
|
||||
backlight = <&backlight>;
|
||||
|
||||
width-mm = <35>;
|
||||
height-mm = <28>;
|
||||
|
||||
panel-timing {
|
||||
hactive = <160>;
|
||||
vactive = <128>;
|
||||
hback-porch = <0>;
|
||||
vback-porch = <0>;
|
||||
clock-frequency = <0>;
|
||||
hfront-porch = <0>;
|
||||
hsync-len = <0>;
|
||||
vfront-porch = <0>;
|
||||
vsync-len = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -241,6 +241,28 @@ Contact: Thomas Zimmermann <tzimmermann@suse.de>, Daniel Vetter
|
||||
|
||||
Level: Advanced
|
||||
|
||||
Benchmark and optimize blitting and format-conversion function
|
||||
--------------------------------------------------------------
|
||||
|
||||
Drawing to dispay memory quickly is crucial for many applications'
|
||||
performance.
|
||||
|
||||
On at least x86-64, sys_imageblit() is significantly slower than
|
||||
cfb_imageblit(), even though both use the same blitting algorithm and
|
||||
the latter is written for I/O memory. It turns out that cfb_imageblit()
|
||||
uses movl instructions, while sys_imageblit apparently does not. This
|
||||
seems to be a problem with gcc's optimizer. DRM's format-conversion
|
||||
helpers might be subject to similar issues.
|
||||
|
||||
Benchmark and optimize fbdev's sys_() helpers and DRM's format-conversion
|
||||
helpers. In cases that can be further optimized, maybe implement a different
|
||||
algorithm. For micro-optimizations, use movl/movq instructions explicitly.
|
||||
That might possibly require architecture-specific helpers (e.g., storel()
|
||||
storeq()).
|
||||
|
||||
Contact: Thomas Zimmermann <tzimmermann@suse.de>
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
drm_framebuffer_funcs and drm_mode_config_funcs.fb_create cleanup
|
||||
-----------------------------------------------------------------
|
||||
@ -475,8 +497,12 @@ This is a really varied tasks with lots of little bits and pieces:
|
||||
achieved by using an IPI to the local processor.
|
||||
|
||||
* There's a massive confusion of different panic handlers. DRM fbdev emulation
|
||||
helpers have one, but on top of that the fbcon code itself also has one. We
|
||||
need to make sure that they stop fighting over each another.
|
||||
helpers had their own (long removed), but on top of that the fbcon code itself
|
||||
also has one. We need to make sure that they stop fighting over each other.
|
||||
This is worked around by checking ``oops_in_progress`` at various entry points
|
||||
into the DRM fbdev emulation helpers. A much cleaner approach here would be to
|
||||
switch fbcon to the `threaded printk support
|
||||
<https://lwn.net/Articles/800946/>`_.
|
||||
|
||||
* ``drm_can_sleep()`` is a mess. It hides real bugs in normal operations and
|
||||
isn't a full solution for panic paths. We need to make sure that it only
|
||||
@ -488,16 +514,15 @@ This is a really varied tasks with lots of little bits and pieces:
|
||||
even spinlocks (because NMI and hardirq can panic too). We need to either
|
||||
make sure to not call such paths, or trylock everything. Really tricky.
|
||||
|
||||
* For the above locking troubles reasons it's pretty much impossible to
|
||||
attempt a synchronous modeset from panic handlers. The only thing we could
|
||||
try to achive is an atomic ``set_base`` of the primary plane, and hope that
|
||||
it shows up. Everything else probably needs to be delayed to some worker or
|
||||
something else which happens later on. Otherwise it just kills the box
|
||||
harder, prevent the panic from going out on e.g. netconsole.
|
||||
* A clean solution would be an entirely separate panic output support in KMS,
|
||||
bypassing the current fbcon support. See `[PATCH v2 0/3] drm: Add panic handling
|
||||
<https://lore.kernel.org/dri-devel/20190311174218.51899-1-noralf@tronnes.org/>`_.
|
||||
|
||||
* There's also proposal for a simplied DRM console instead of the full-blown
|
||||
fbcon and DRM fbdev emulation. Any kind of panic handling tricks should
|
||||
obviously work for both console, in case we ever get kmslog merged.
|
||||
* Encoding the actual oops and preceding dmesg in a QR might help with the
|
||||
dread "important stuff scrolled away" problem. See `[RFC][PATCH] Oops messages
|
||||
transfer using QR codes
|
||||
<https://lore.kernel.org/lkml/1446217392-11981-1-git-send-email-alexandru.murtaza@intel.com/>`_
|
||||
for some example code that could be reused.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
|
@ -6112,6 +6112,14 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
|
||||
F: drivers/gpu/drm/tiny/mi0283qt.c
|
||||
|
||||
DRM DRIVER FOR MIPI DBI compatible panels
|
||||
M: Noralf Trønnes <noralf@tronnes.org>
|
||||
S: Maintained
|
||||
W: https://github.com/notro/panel-mipi-dbi/wiki
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml
|
||||
F: drivers/gpu/drm/tiny/panel-mipi-dbi.c
|
||||
|
||||
DRM DRIVER FOR MSM ADRENO GPU
|
||||
M: Rob Clark <robdclark@gmail.com>
|
||||
M: Sean Paul <sean@poorly.run>
|
||||
|
@ -12,6 +12,7 @@ struct aspeed_gfx {
|
||||
struct regmap *scu;
|
||||
|
||||
u32 dac_reg;
|
||||
u32 int_clr_reg;
|
||||
u32 vga_scratch_reg;
|
||||
u32 throd_val;
|
||||
u32 scan_line_max;
|
||||
|
@ -61,6 +61,7 @@
|
||||
|
||||
struct aspeed_gfx_config {
|
||||
u32 dac_reg; /* DAC register in SCU */
|
||||
u32 int_clear_reg; /* Interrupt clear register */
|
||||
u32 vga_scratch_reg; /* VGA scratch register in SCU */
|
||||
u32 throd_val; /* Default Threshold Seting */
|
||||
u32 scan_line_max; /* Max memory size of one scan line */
|
||||
@ -68,6 +69,7 @@ struct aspeed_gfx_config {
|
||||
|
||||
static const struct aspeed_gfx_config ast2400_config = {
|
||||
.dac_reg = 0x2c,
|
||||
.int_clear_reg = 0x60,
|
||||
.vga_scratch_reg = 0x50,
|
||||
.throd_val = CRT_THROD_LOW(0x1e) | CRT_THROD_HIGH(0x12),
|
||||
.scan_line_max = 64,
|
||||
@ -75,14 +77,24 @@ static const struct aspeed_gfx_config ast2400_config = {
|
||||
|
||||
static const struct aspeed_gfx_config ast2500_config = {
|
||||
.dac_reg = 0x2c,
|
||||
.int_clear_reg = 0x60,
|
||||
.vga_scratch_reg = 0x50,
|
||||
.throd_val = CRT_THROD_LOW(0x24) | CRT_THROD_HIGH(0x3c),
|
||||
.scan_line_max = 128,
|
||||
};
|
||||
|
||||
static const struct aspeed_gfx_config ast2600_config = {
|
||||
.dac_reg = 0xc0,
|
||||
.int_clear_reg = 0x68,
|
||||
.vga_scratch_reg = 0x50,
|
||||
.throd_val = CRT_THROD_LOW(0x50) | CRT_THROD_HIGH(0x70),
|
||||
.scan_line_max = 128,
|
||||
};
|
||||
|
||||
static const struct of_device_id aspeed_gfx_match[] = {
|
||||
{ .compatible = "aspeed,ast2400-gfx", .data = &ast2400_config },
|
||||
{ .compatible = "aspeed,ast2500-gfx", .data = &ast2500_config },
|
||||
{ .compatible = "aspeed,ast2600-gfx", .data = &ast2600_config },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_gfx_match);
|
||||
@ -120,7 +132,7 @@ static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data)
|
||||
|
||||
if (reg & CRT_CTRL_VERTICAL_INTR_STS) {
|
||||
drm_crtc_handle_vblank(&priv->pipe.crtc);
|
||||
writel(reg, priv->base + CRT_CTRL1);
|
||||
writel(reg, priv->base + priv->int_clr_reg);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -148,6 +160,7 @@ static int aspeed_gfx_load(struct drm_device *drm)
|
||||
config = match->data;
|
||||
|
||||
priv->dac_reg = config->dac_reg;
|
||||
priv->int_clr_reg = config->int_clear_reg;
|
||||
priv->vga_scratch_reg = config->vga_scratch_reg;
|
||||
priv->throd_val = config->throd_val;
|
||||
priv->scan_line_max = config->scan_line_max;
|
||||
|
@ -253,6 +253,8 @@ static int anx7625_aux_trans(struct anx7625_data *ctx, u8 op, u32 address,
|
||||
addrm = (address >> 8) & 0xFF;
|
||||
addrh = (address >> 16) & 0xFF;
|
||||
|
||||
if (!is_write)
|
||||
op &= ~DP_AUX_I2C_MOT;
|
||||
cmd = DPCD_CMD(len, op);
|
||||
|
||||
/* Set command and length */
|
||||
@ -2736,8 +2738,8 @@ static int anx7625_i2c_remove(struct i2c_client *client)
|
||||
|
||||
if (platform->hdcp_workqueue) {
|
||||
cancel_delayed_work(&platform->hdcp_work);
|
||||
flush_workqueue(platform->workqueue);
|
||||
destroy_workqueue(platform->workqueue);
|
||||
flush_workqueue(platform->hdcp_workqueue);
|
||||
destroy_workqueue(platform->hdcp_workqueue);
|
||||
}
|
||||
|
||||
if (!platform->pdata.low_power_mode)
|
||||
|
@ -1284,6 +1284,7 @@ static const struct of_device_id cdns_dsi_of_match[] = {
|
||||
{ .compatible = "cdns,dsi" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_dsi_of_match);
|
||||
|
||||
static struct platform_driver cdns_dsi_platform_driver = {
|
||||
.probe = cdns_dsi_drm_probe,
|
||||
|
@ -191,7 +191,6 @@ static const struct drm_bridge_funcs chipone_bridge_funcs = {
|
||||
static int chipone_parse_dt(struct chipone *icn)
|
||||
{
|
||||
struct device *dev = icn->dev;
|
||||
struct drm_panel *panel;
|
||||
int ret;
|
||||
|
||||
icn->vdd1 = devm_regulator_get_optional(dev, "vdd1");
|
||||
@ -227,11 +226,7 @@ static int chipone_parse_dt(struct chipone *icn)
|
||||
return PTR_ERR(icn->enable_gpio);
|
||||
}
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
icn->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||
icn->panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
|
||||
if (IS_ERR(icn->panel_bridge))
|
||||
return PTR_ERR(icn->panel_bridge);
|
||||
|
||||
|
@ -289,7 +289,7 @@
|
||||
#define WORD_LENGTH_20BIT 2
|
||||
#define WORD_LENGTH_24BIT 3
|
||||
#define DEBUGFS_DIR_NAME "it6505-debugfs"
|
||||
#define READ_BUFFER_SIZE 200
|
||||
#define READ_BUFFER_SIZE 400
|
||||
|
||||
/* Vendor option */
|
||||
#define HDCP_DESIRED 1
|
||||
@ -3074,7 +3074,7 @@ static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf,
|
||||
struct it6505 *it6505 = file->private_data;
|
||||
struct drm_display_mode *vid = &it6505->video_info;
|
||||
u8 read_buf[READ_BUFFER_SIZE];
|
||||
u8 *str = read_buf, *end = read_buf + PAGE_SIZE;
|
||||
u8 *str = read_buf, *end = read_buf + READ_BUFFER_SIZE;
|
||||
ssize_t ret, count;
|
||||
|
||||
if (!it6505)
|
||||
|
@ -332,17 +332,13 @@ static int nwl_dsi_config_dpi(struct nwl_dsi *dsi)
|
||||
|
||||
static int nwl_dsi_init_interrupts(struct nwl_dsi *dsi)
|
||||
{
|
||||
u32 irq_enable;
|
||||
|
||||
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, 0xffffffff);
|
||||
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK2, 0x7);
|
||||
|
||||
irq_enable = ~(u32)(NWL_DSI_TX_PKT_DONE_MASK |
|
||||
NWL_DSI_RX_PKT_HDR_RCVD_MASK |
|
||||
NWL_DSI_TX_FIFO_OVFLW_MASK |
|
||||
NWL_DSI_HS_TX_TIMEOUT_MASK);
|
||||
u32 irq_enable = ~(u32)(NWL_DSI_TX_PKT_DONE_MASK |
|
||||
NWL_DSI_RX_PKT_HDR_RCVD_MASK |
|
||||
NWL_DSI_TX_FIFO_OVFLW_MASK |
|
||||
NWL_DSI_HS_TX_TIMEOUT_MASK);
|
||||
|
||||
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, irq_enable);
|
||||
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK2, 0x7);
|
||||
|
||||
return nwl_dsi_clear_error(dsi);
|
||||
}
|
||||
|
@ -208,16 +208,6 @@ bool drm_dp_128b132b_link_training_failed(const u8 link_status[DP_LINK_STATUS_SI
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_128b132b_link_training_failed);
|
||||
|
||||
u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
unsigned int lane)
|
||||
{
|
||||
unsigned int offset = DP_ADJUST_REQUEST_POST_CURSOR2;
|
||||
u8 value = dp_link_status(link_status, offset);
|
||||
|
||||
return (value >> (lane << 1)) & 0x3;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor);
|
||||
|
||||
static int __8b10b_clock_recovery_delay_us(const struct drm_dp_aux *aux, u8 rd_interval)
|
||||
{
|
||||
if (rd_interval > 4)
|
||||
|
@ -243,11 +243,36 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
|
||||
void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state,
|
||||
struct drm_plane *plane)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
plane_state->plane = plane;
|
||||
plane_state->rotation = DRM_MODE_ROTATE_0;
|
||||
|
||||
plane_state->alpha = DRM_BLEND_ALPHA_OPAQUE;
|
||||
plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
|
||||
|
||||
if (plane->color_encoding_property) {
|
||||
if (!drm_object_property_get_default_value(&plane->base,
|
||||
plane->color_encoding_property,
|
||||
&val))
|
||||
plane_state->color_encoding = val;
|
||||
}
|
||||
|
||||
if (plane->color_range_property) {
|
||||
if (!drm_object_property_get_default_value(&plane->base,
|
||||
plane->color_range_property,
|
||||
&val))
|
||||
plane_state->color_range = val;
|
||||
}
|
||||
|
||||
if (plane->zpos_property) {
|
||||
if (!drm_object_property_get_default_value(&plane->base,
|
||||
plane->zpos_property,
|
||||
&val)) {
|
||||
plane_state->zpos = val;
|
||||
plane_state->normalized_zpos = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset);
|
||||
|
||||
|
@ -297,11 +297,26 @@ int drm_object_property_set_value(struct drm_mode_object *obj,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_object_property_set_value);
|
||||
|
||||
static int __drm_object_property_get_prop_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t *val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < obj->properties->count; i++) {
|
||||
if (obj->properties->properties[i] == property) {
|
||||
*val = obj->properties->values[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int __drm_object_property_get_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t *val)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* read-only properties bypass atomic mechanism and still store
|
||||
* their value in obj->properties->values[].. mostly to avoid
|
||||
@ -311,15 +326,7 @@ static int __drm_object_property_get_value(struct drm_mode_object *obj,
|
||||
!(property->flags & DRM_MODE_PROP_IMMUTABLE))
|
||||
return drm_atomic_get_property(obj, property, val);
|
||||
|
||||
for (i = 0; i < obj->properties->count; i++) {
|
||||
if (obj->properties->properties[i] == property) {
|
||||
*val = obj->properties->values[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
return __drm_object_property_get_prop_value(obj, property, val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,6 +355,32 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_object_property_get_value);
|
||||
|
||||
/**
|
||||
* drm_object_property_get_default_value - retrieve the default value of a
|
||||
* property when in atomic mode.
|
||||
* @obj: drm mode object to get property value from
|
||||
* @property: property to retrieve
|
||||
* @val: storage for the property value
|
||||
*
|
||||
* This function retrieves the default state of the given property as passed in
|
||||
* to drm_object_attach_property
|
||||
*
|
||||
* Only atomic drivers should call this function directly, as for non-atomic
|
||||
* drivers it will return the current value.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_object_property_get_default_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t *val)
|
||||
{
|
||||
WARN_ON(!drm_drv_uses_atomic_modeset(property->dev));
|
||||
|
||||
return __drm_object_property_get_prop_value(obj, property, val);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_object_property_get_default_value);
|
||||
|
||||
/* helper for getconnector and getproperties ioctls */
|
||||
int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
|
||||
uint32_t __user *prop_ptr,
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/list_sort.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <video/of_display_timing.h>
|
||||
#include <video/of_videomode.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
@ -127,7 +128,7 @@ EXPORT_SYMBOL(drm_mode_probed_add);
|
||||
* according to the hdisplay, vdisplay, vrefresh.
|
||||
* It is based from the VESA(TM) Coordinated Video Timing Generator by
|
||||
* Graham Loveridge April 9, 2003 available at
|
||||
* http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
|
||||
* http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
|
||||
*
|
||||
* And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
|
||||
* What I have done is to translate it by using integer calculation.
|
||||
@ -727,6 +728,54 @@ int of_get_drm_display_mode(struct device_node *np,
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
|
||||
|
||||
/**
|
||||
* of_get_drm_panel_display_mode - get a panel-timing drm_display_mode from devicetree
|
||||
* @np: device_node with the panel-timing specification
|
||||
* @dmode: will be set to the return value
|
||||
* @bus_flags: information about pixelclk, sync and DE polarity
|
||||
*
|
||||
* The Device Tree properties width-mm and height-mm will be read and set on
|
||||
* the display mode if they are present.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative error code on failure.
|
||||
*/
|
||||
int of_get_drm_panel_display_mode(struct device_node *np,
|
||||
struct drm_display_mode *dmode, u32 *bus_flags)
|
||||
{
|
||||
u32 width_mm = 0, height_mm = 0;
|
||||
struct display_timing timing;
|
||||
struct videomode vm;
|
||||
int ret;
|
||||
|
||||
ret = of_get_display_timing(np, "panel-timing", &timing);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
videomode_from_timing(&timing, &vm);
|
||||
|
||||
memset(dmode, 0, sizeof(*dmode));
|
||||
drm_display_mode_from_videomode(&vm, dmode);
|
||||
if (bus_flags)
|
||||
drm_bus_flags_from_videomode(&vm, bus_flags);
|
||||
|
||||
ret = of_property_read_u32(np, "width-mm", &width_mm);
|
||||
if (ret && ret != -EINVAL)
|
||||
return ret;
|
||||
|
||||
ret = of_property_read_u32(np, "height-mm", &height_mm);
|
||||
if (ret && ret != -EINVAL)
|
||||
return ret;
|
||||
|
||||
dmode->width_mm = width_mm;
|
||||
dmode->height_mm = height_mm;
|
||||
|
||||
drm_mode_debug_printmodeline(dmode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_get_drm_panel_display_mode);
|
||||
#endif /* CONFIG_OF */
|
||||
#endif /* CONFIG_VIDEOMODE_HELPERS */
|
||||
|
||||
|
@ -249,6 +249,21 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
|
||||
if (panel)
|
||||
*panel = NULL;
|
||||
|
||||
/**
|
||||
* Devices can also be child nodes when we also control that device
|
||||
* through the upstream device (ie, MIPI-DCS for a MIPI-DSI device).
|
||||
*
|
||||
* Lookup for a child node of the given parent that isn't either port
|
||||
* or ports.
|
||||
*/
|
||||
for_each_available_child_of_node(np, remote) {
|
||||
if (of_node_name_eq(remote, "port") ||
|
||||
of_node_name_eq(remote, "ports"))
|
||||
continue;
|
||||
|
||||
goto of_find_panel_or_bridge;
|
||||
}
|
||||
|
||||
/*
|
||||
* of_graph_get_remote_node() produces a noisy error message if port
|
||||
* node isn't found and the absence of the port is a legit case here,
|
||||
@ -259,6 +274,8 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
|
||||
return -ENODEV;
|
||||
|
||||
remote = of_graph_get_remote_node(np, port, endpoint);
|
||||
|
||||
of_find_panel_or_bridge:
|
||||
if (!remote)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -48,6 +48,8 @@ static void mdp5_plane_destroy(struct drm_plane *plane)
|
||||
static void mdp5_plane_install_properties(struct drm_plane *plane,
|
||||
struct drm_mode_object *obj)
|
||||
{
|
||||
unsigned int zpos;
|
||||
|
||||
drm_plane_create_rotation_property(plane,
|
||||
DRM_MODE_ROTATE_0,
|
||||
DRM_MODE_ROTATE_0 |
|
||||
@ -59,7 +61,12 @@ static void mdp5_plane_install_properties(struct drm_plane *plane,
|
||||
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
|
||||
BIT(DRM_MODE_BLEND_PREMULTI) |
|
||||
BIT(DRM_MODE_BLEND_COVERAGE));
|
||||
drm_plane_create_zpos_property(plane, 1, 1, 255);
|
||||
|
||||
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
|
||||
zpos = STAGE_BASE;
|
||||
else
|
||||
zpos = STAGE0 + drm_plane_index(plane);
|
||||
drm_plane_create_zpos_property(plane, zpos, 1, 255);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -91,13 +98,6 @@ static void mdp5_plane_reset(struct drm_plane *plane)
|
||||
|
||||
kfree(to_mdp5_plane_state(plane->state));
|
||||
mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
|
||||
|
||||
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
|
||||
mdp5_state->base.zpos = STAGE_BASE;
|
||||
else
|
||||
mdp5_state->base.zpos = STAGE0 + drm_plane_index(plane);
|
||||
mdp5_state->base.normalized_zpos = mdp5_state->base.zpos;
|
||||
|
||||
__drm_atomic_helper_plane_reset(plane, &mdp5_state->base);
|
||||
}
|
||||
|
||||
|
@ -635,8 +635,6 @@ nv50_wndw_reset(struct drm_plane *plane)
|
||||
plane->funcs->atomic_destroy_state(plane, plane->state);
|
||||
|
||||
__drm_atomic_helper_plane_reset(plane, &asyw->state);
|
||||
plane->state->zpos = nv50_wndw_zpos_default(plane);
|
||||
plane->state->normalized_zpos = nv50_wndw_zpos_default(plane);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1,353 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
* Copyright © 2010 Francisco Jerez <currojerez@riseup.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Modified by Ben Skeggs <bskeggs@redhat.com> to match kernel list APIs */
|
||||
|
||||
#ifndef _XORG_LIST_H_
|
||||
#define _XORG_LIST_H_
|
||||
|
||||
/**
|
||||
* @file Classic doubly-link circular list implementation.
|
||||
* For real usage examples of the linked list, see the file test/list.c
|
||||
*
|
||||
* Example:
|
||||
* We need to keep a list of struct foo in the parent struct bar, i.e. what
|
||||
* we want is something like this.
|
||||
*
|
||||
* struct bar {
|
||||
* ...
|
||||
* struct foo *list_of_foos; -----> struct foo {}, struct foo {}, struct foo{}
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* We need one list head in bar and a list element in all list_of_foos (both are of
|
||||
* data type 'struct list_head').
|
||||
*
|
||||
* struct bar {
|
||||
* ...
|
||||
* struct list_head list_of_foos;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* struct foo {
|
||||
* ...
|
||||
* struct list_head entry;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* Now we initialize the list head:
|
||||
*
|
||||
* struct bar bar;
|
||||
* ...
|
||||
* INIT_LIST_HEAD(&bar.list_of_foos);
|
||||
*
|
||||
* Then we create the first element and add it to this list:
|
||||
*
|
||||
* struct foo *foo = malloc(...);
|
||||
* ....
|
||||
* list_add(&foo->entry, &bar.list_of_foos);
|
||||
*
|
||||
* Repeat the above for each element you want to add to the list. Deleting
|
||||
* works with the element itself.
|
||||
* list_del(&foo->entry);
|
||||
* free(foo);
|
||||
*
|
||||
* Note: calling list_del(&bar.list_of_foos) will set bar.list_of_foos to an empty
|
||||
* list again.
|
||||
*
|
||||
* Looping through the list requires a 'struct foo' as iterator and the
|
||||
* name of the field the subnodes use.
|
||||
*
|
||||
* struct foo *iterator;
|
||||
* list_for_each_entry(iterator, &bar.list_of_foos, entry) {
|
||||
* if (iterator->something == ...)
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* Note: You must not call list_del() on the iterator if you continue the
|
||||
* loop. You need to run the safe for-each loop instead:
|
||||
*
|
||||
* struct foo *iterator, *next;
|
||||
* list_for_each_entry_safe(iterator, next, &bar.list_of_foos, entry) {
|
||||
* if (...)
|
||||
* list_del(&iterator->entry);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The linkage struct for list nodes. This struct must be part of your
|
||||
* to-be-linked struct. struct list_head is required for both the head of the
|
||||
* list and for each list node.
|
||||
*
|
||||
* Position and name of the struct list_head field is irrelevant.
|
||||
* There are no requirements that elements of a list are of the same type.
|
||||
* There are no requirements for a list head, any struct list_head can be a list
|
||||
* head.
|
||||
*/
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the list as an empty list.
|
||||
*
|
||||
* Example:
|
||||
* INIT_LIST_HEAD(&bar->list_of_foos);
|
||||
*
|
||||
* @param The list to initialized.
|
||||
*/
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
static inline void
|
||||
INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
list->next = list->prev = list;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__list_add(struct list_head *entry,
|
||||
struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
next->prev = entry;
|
||||
entry->next = next;
|
||||
entry->prev = prev;
|
||||
prev->next = entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new element after the given list head. The new element does not
|
||||
* need to be initialised as empty list.
|
||||
* The list changes from:
|
||||
* head → some element → ...
|
||||
* to
|
||||
* head → new element → older element → ...
|
||||
*
|
||||
* Example:
|
||||
* struct foo *newfoo = malloc(...);
|
||||
* list_add(&newfoo->entry, &bar->list_of_foos);
|
||||
*
|
||||
* @param entry The new element to prepend to the list.
|
||||
* @param head The existing list.
|
||||
*/
|
||||
static inline void
|
||||
list_add(struct list_head *entry, struct list_head *head)
|
||||
{
|
||||
__list_add(entry, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a new element to the end of the list given with this list head.
|
||||
*
|
||||
* The list changes from:
|
||||
* head → some element → ... → lastelement
|
||||
* to
|
||||
* head → some element → ... → lastelement → new element
|
||||
*
|
||||
* Example:
|
||||
* struct foo *newfoo = malloc(...);
|
||||
* list_add_tail(&newfoo->entry, &bar->list_of_foos);
|
||||
*
|
||||
* @param entry The new element to prepend to the list.
|
||||
* @param head The existing list.
|
||||
*/
|
||||
static inline void
|
||||
list_add_tail(struct list_head *entry, struct list_head *head)
|
||||
{
|
||||
__list_add(entry, head->prev, head);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__list_del(struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the element from the list it is in. Using this function will reset
|
||||
* the pointers to/from this element so it is removed from the list. It does
|
||||
* NOT free the element itself or manipulate it otherwise.
|
||||
*
|
||||
* Using list_del on a pure list head (like in the example at the top of
|
||||
* this file) will NOT remove the first element from
|
||||
* the list but rather reset the list as empty list.
|
||||
*
|
||||
* Example:
|
||||
* list_del(&foo->entry);
|
||||
*
|
||||
* @param entry The element to remove.
|
||||
*/
|
||||
static inline void
|
||||
list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the list is empty.
|
||||
*
|
||||
* Example:
|
||||
* list_empty(&bar->list_of_foos);
|
||||
*
|
||||
* @return True if the list contains one or more elements or False otherwise.
|
||||
*/
|
||||
static inline bool
|
||||
list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the container of this list element.
|
||||
*
|
||||
* Example:
|
||||
* struct foo* f;
|
||||
* f = container_of(&foo->entry, struct foo, entry);
|
||||
* assert(f == foo);
|
||||
*
|
||||
* @param ptr Pointer to the struct list_head.
|
||||
* @param type Data type of the list element.
|
||||
* @param member Member name of the struct list_head field in the list element.
|
||||
* @return A pointer to the data struct containing the list head.
|
||||
*/
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) \
|
||||
(type *)((char *)(ptr) - (char *) &((type *)0)->member)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Alias of container_of
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* Retrieve the first list entry for the given list pointer.
|
||||
*
|
||||
* Example:
|
||||
* struct foo *first;
|
||||
* first = list_first_entry(&bar->list_of_foos, struct foo, list_of_foos);
|
||||
*
|
||||
* @param ptr The list head
|
||||
* @param type Data type of the list element to retrieve
|
||||
* @param member Member name of the struct list_head field in the list element.
|
||||
* @return A pointer to the first list element.
|
||||
*/
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* Retrieve the last list entry for the given listpointer.
|
||||
*
|
||||
* Example:
|
||||
* struct foo *first;
|
||||
* first = list_last_entry(&bar->list_of_foos, struct foo, list_of_foos);
|
||||
*
|
||||
* @param ptr The list head
|
||||
* @param type Data type of the list element to retrieve
|
||||
* @param member Member name of the struct list_head field in the list element.
|
||||
* @return A pointer to the last list element.
|
||||
*/
|
||||
#define list_last_entry(ptr, type, member) \
|
||||
list_entry((ptr)->prev, type, member)
|
||||
|
||||
#define __container_of(ptr, sample, member) \
|
||||
(void *)container_of((ptr), typeof(*(sample)), member)
|
||||
|
||||
/**
|
||||
* Loop through the list given by head and set pos to struct in the list.
|
||||
*
|
||||
* Example:
|
||||
* struct foo *iterator;
|
||||
* list_for_each_entry(iterator, &bar->list_of_foos, entry) {
|
||||
* [modify iterator]
|
||||
* }
|
||||
*
|
||||
* This macro is not safe for node deletion. Use list_for_each_entry_safe
|
||||
* instead.
|
||||
*
|
||||
* @param pos Iterator variable of the type of the list elements.
|
||||
* @param head List head
|
||||
* @param member Member name of the struct list_head in the list elements.
|
||||
*
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = __container_of((head)->next, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = __container_of(pos->member.next, pos, member))
|
||||
|
||||
/**
|
||||
* Loop through the list, keeping a backup pointer to the element. This
|
||||
* macro allows for the deletion of a list element while looping through the
|
||||
* list.
|
||||
*
|
||||
* See list_for_each_entry for more details.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, tmp, head, member) \
|
||||
for (pos = __container_of((head)->next, pos, member), \
|
||||
tmp = __container_of(pos->member.next, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = tmp, tmp = __container_of(pos->member.next, tmp, member))
|
||||
|
||||
|
||||
#define list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = __container_of((head)->prev, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = __container_of(pos->member.prev, pos, member))
|
||||
|
||||
#define list_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = __container_of(pos->member.next, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = __container_of(pos->member.next, pos, member))
|
||||
|
||||
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
||||
for (pos = __container_of(pos->member.prev, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = __container_of(pos->member.prev, pos, member))
|
||||
|
||||
#define list_for_each_entry_from(pos, head, member) \
|
||||
for (; \
|
||||
&pos->member != (head); \
|
||||
pos = __container_of(pos->member.next, pos, member))
|
||||
|
||||
#endif
|
@ -403,7 +403,6 @@ void omap_plane_install_properties(struct drm_plane *plane,
|
||||
|
||||
static void omap_plane_reset(struct drm_plane *plane)
|
||||
{
|
||||
struct omap_plane *omap_plane = to_omap_plane(plane);
|
||||
struct omap_plane_state *omap_state;
|
||||
|
||||
if (plane->state)
|
||||
@ -414,15 +413,6 @@ static void omap_plane_reset(struct drm_plane *plane)
|
||||
return;
|
||||
|
||||
__drm_atomic_helper_plane_reset(plane, &omap_state->base);
|
||||
|
||||
/*
|
||||
* Set the zpos default depending on whether we are a primary or overlay
|
||||
* plane.
|
||||
*/
|
||||
plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
|
||||
? 0 : omap_plane->id;
|
||||
plane->state->color_encoding = DRM_COLOR_YCBCR_BT601;
|
||||
plane->state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
|
||||
}
|
||||
|
||||
static struct drm_plane_state *
|
||||
@ -533,6 +523,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
|
||||
unsigned int num_planes = dispc_get_num_ovls(priv->dispc);
|
||||
struct drm_plane *plane;
|
||||
struct omap_plane *omap_plane;
|
||||
unsigned int zpos;
|
||||
int ret;
|
||||
u32 nformats;
|
||||
const u32 *formats;
|
||||
@ -564,7 +555,16 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
|
||||
drm_plane_helper_add(plane, &omap_plane_helper_funcs);
|
||||
|
||||
omap_plane_install_properties(plane, &plane->base);
|
||||
drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1);
|
||||
|
||||
/*
|
||||
* Set the zpos default depending on whether we are a primary or overlay
|
||||
* plane.
|
||||
*/
|
||||
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
|
||||
zpos = 0;
|
||||
else
|
||||
zpos = omap_plane->id;
|
||||
drm_plane_create_zpos_property(plane, zpos, 0, num_planes - 1);
|
||||
drm_plane_create_alpha_property(plane);
|
||||
drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) |
|
||||
BIT(DRM_MODE_BLEND_COVERAGE));
|
||||
|
@ -3058,6 +3058,7 @@ static const struct drm_display_mode rocktech_rk101ii01d_ct_mode = {
|
||||
|
||||
static const struct panel_desc rocktech_rk101ii01d_ct = {
|
||||
.modes = &rocktech_rk101ii01d_ct_mode,
|
||||
.bpc = 8,
|
||||
.num_modes = 1,
|
||||
.size = {
|
||||
.width = 217,
|
||||
|
@ -562,7 +562,7 @@ static int panfrost_probe(struct platform_device *pdev)
|
||||
|
||||
pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
|
||||
|
||||
/* Allocate and initialze the DRM device. */
|
||||
/* Allocate and initialize the DRM device. */
|
||||
ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev);
|
||||
if (IS_ERR(ddev))
|
||||
return PTR_ERR(ddev);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (C) 2019 Arm Ltd.
|
||||
*
|
||||
* Based on msm_gem_freedreno.c:
|
||||
|
@ -14,7 +14,7 @@
|
||||
*/
|
||||
enum panfrost_hw_issue {
|
||||
/* Need way to guarantee that all previously-translated memory accesses
|
||||
* are commited */
|
||||
* are committed */
|
||||
HW_ISSUE_6367,
|
||||
|
||||
/* On job complete with non-done the cache is not flushed */
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
|
||||
|
||||
#include <drm/panfrost_drm.h>
|
||||
|
@ -293,7 +293,7 @@
|
||||
#define AS_FAULTADDRESS_LO(as) (MMU_AS(as) + 0x20) /* (RO) Fault Address for address space n, low word */
|
||||
#define AS_FAULTADDRESS_HI(as) (MMU_AS(as) + 0x24) /* (RO) Fault Address for address space n, high word */
|
||||
#define AS_STATUS(as) (MMU_AS(as) + 0x28) /* (RO) Status flags for address space n */
|
||||
/* Additional Bifrost AS regsiters */
|
||||
/* Additional Bifrost AS registers */
|
||||
#define AS_TRANSCFG_LO(as) (MMU_AS(as) + 0x30) /* (RW) Translation table configuration for address space n, low word */
|
||||
#define AS_TRANSCFG_HI(as) (MMU_AS(as) + 0x34) /* (RW) Translation table configuration for address space n, high word */
|
||||
#define AS_FAULTEXTRA_LO(as) (MMU_AS(as) + 0x38) /* (RO) Secondary fault address for address space n, low word */
|
||||
|
@ -704,7 +704,6 @@ static void rcar_du_plane_reset(struct drm_plane *plane)
|
||||
state->hwindex = -1;
|
||||
state->source = RCAR_DU_PLANE_MEMORY;
|
||||
state->colorkey = RCAR_DU_COLORKEY_NONE;
|
||||
state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
|
||||
}
|
||||
|
||||
static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
|
||||
|
@ -353,7 +353,6 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
|
||||
return;
|
||||
|
||||
__drm_atomic_helper_plane_reset(plane, &state->state);
|
||||
state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
|
||||
}
|
||||
|
||||
static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
|
||||
|
@ -579,7 +579,7 @@ static const struct drm_simple_display_pipe_funcs ssd130x_pipe_funcs = {
|
||||
static int ssd130x_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev);
|
||||
struct drm_display_mode *mode = &ssd130x->mode;
|
||||
struct drm_display_mode *mode;
|
||||
struct device *dev = ssd130x->dev;
|
||||
|
||||
mode = drm_mode_duplicate(connector->dev, &ssd130x->mode);
|
||||
|
@ -351,7 +351,7 @@ static const struct drm_plane_funcs sti_cursor_plane_helpers_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.destroy = drm_plane_cleanup,
|
||||
.reset = sti_plane_reset,
|
||||
.reset = drm_atomic_helper_plane_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
.late_register = sti_cursor_late_register,
|
||||
|
@ -905,7 +905,7 @@ static const struct drm_plane_funcs sti_gdp_plane_helpers_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.destroy = drm_plane_cleanup,
|
||||
.reset = sti_plane_reset,
|
||||
.reset = drm_atomic_helper_plane_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
.late_register = sti_gdp_late_register,
|
||||
|
@ -1283,7 +1283,7 @@ static const struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.destroy = drm_plane_cleanup,
|
||||
.reset = sti_plane_reset,
|
||||
.reset = drm_atomic_helper_plane_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
.late_register = sti_hqvdp_late_register,
|
||||
|
@ -112,12 +112,6 @@ static int sti_plane_get_default_zpos(enum drm_plane_type type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sti_plane_reset(struct drm_plane *plane)
|
||||
{
|
||||
drm_atomic_helper_plane_reset(plane);
|
||||
plane->state->zpos = sti_plane_get_default_zpos(plane->type);
|
||||
}
|
||||
|
||||
static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane,
|
||||
enum drm_plane_type type)
|
||||
{
|
||||
|
@ -81,5 +81,4 @@ void sti_plane_update_fps(struct sti_plane *plane,
|
||||
|
||||
void sti_plane_init_property(struct sti_plane *plane,
|
||||
enum drm_plane_type type);
|
||||
void sti_plane_reset(struct drm_plane *plane);
|
||||
#endif
|
||||
|
@ -77,6 +77,7 @@
|
||||
#define LTDC_CPSR 0x0044 /* Current Position Status */
|
||||
#define LTDC_CDSR 0x0048 /* Current Display Status */
|
||||
#define LTDC_EDCR 0x0060 /* External Display Control */
|
||||
#define LTDC_CCRCR 0x007C /* Computed CRC value */
|
||||
#define LTDC_FUT 0x0090 /* Fifo underrun Threshold */
|
||||
|
||||
/* Layer register offsets */
|
||||
@ -121,6 +122,7 @@
|
||||
|
||||
#define GCR_LTDCEN BIT(0) /* LTDC ENable */
|
||||
#define GCR_DEN BIT(16) /* Dither ENable */
|
||||
#define GCR_CRCEN BIT(19) /* CRC ENable */
|
||||
#define GCR_PCPOL BIT(28) /* Pixel Clock POLarity-Inverted */
|
||||
#define GCR_DEPOL BIT(29) /* Data Enable POLarity-High */
|
||||
#define GCR_VSPOL BIT(30) /* Vertical Synchro POLarity-High */
|
||||
@ -227,6 +229,13 @@
|
||||
|
||||
#define NB_PF 8 /* Max nb of HW pixel format */
|
||||
|
||||
/*
|
||||
* Skip the first value and the second in case CRC was enabled during
|
||||
* the thread irq. This is to be sure CRC value is relevant for the
|
||||
* frame.
|
||||
*/
|
||||
#define CRC_SKIP_FRAMES 2
|
||||
|
||||
enum ltdc_pix_fmt {
|
||||
PF_NONE,
|
||||
/* RGB formats */
|
||||
@ -624,7 +633,8 @@ static inline void ltdc_set_ycbcr_config(struct drm_plane *plane, u32 drm_pix_fm
|
||||
break;
|
||||
default:
|
||||
/* RGB or not a YCbCr supported format */
|
||||
break;
|
||||
DRM_ERROR("Unsupported pixel format: %u\n", drm_pix_fmt);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable limited range */
|
||||
@ -664,6 +674,26 @@ static inline void ltdc_set_ycbcr_coeffs(struct drm_plane *plane)
|
||||
ltdc_ycbcr2rgb_coeffs[enc][ran][1]);
|
||||
}
|
||||
|
||||
static inline void ltdc_irq_crc_handle(struct ltdc_device *ldev,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
u32 crc;
|
||||
int ret;
|
||||
|
||||
if (ldev->crc_skip_count < CRC_SKIP_FRAMES) {
|
||||
ldev->crc_skip_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the CRC of the frame */
|
||||
ret = regmap_read(ldev->regmap, LTDC_CCRCR, &crc);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
/* Report to DRM the CRC (hw dependent feature) */
|
||||
drm_crtc_add_crc_entry(crtc, true, drm_crtc_accurate_vblank_count(crtc), &crc);
|
||||
}
|
||||
|
||||
static irqreturn_t ltdc_irq_thread(int irq, void *arg)
|
||||
{
|
||||
struct drm_device *ddev = arg;
|
||||
@ -671,9 +701,14 @@ static irqreturn_t ltdc_irq_thread(int irq, void *arg)
|
||||
struct drm_crtc *crtc = drm_crtc_from_index(ddev, 0);
|
||||
|
||||
/* Line IRQ : trigger the vblank event */
|
||||
if (ldev->irq_status & ISR_LIF)
|
||||
if (ldev->irq_status & ISR_LIF) {
|
||||
drm_crtc_handle_vblank(crtc);
|
||||
|
||||
/* Early return if CRC is not active */
|
||||
if (ldev->crc_active)
|
||||
ltdc_irq_crc_handle(ldev, crtc);
|
||||
}
|
||||
|
||||
/* Save FIFO Underrun & Transfer Error status */
|
||||
mutex_lock(&ldev->err_lock);
|
||||
if (ldev->irq_status & ISR_FUIF)
|
||||
@ -1079,6 +1114,48 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE);
|
||||
}
|
||||
|
||||
static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source)
|
||||
{
|
||||
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
if (!crtc)
|
||||
return -ENODEV;
|
||||
|
||||
if (source && strcmp(source, "auto") == 0) {
|
||||
ldev->crc_active = true;
|
||||
ret = regmap_set_bits(ldev->regmap, LTDC_GCR, GCR_CRCEN);
|
||||
} else if (!source) {
|
||||
ldev->crc_active = false;
|
||||
ret = regmap_clear_bits(ldev->regmap, LTDC_GCR, GCR_CRCEN);
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
ldev->crc_skip_count = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltdc_crtc_verify_crc_source(struct drm_crtc *crtc,
|
||||
const char *source, size_t *values_cnt)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
if (!crtc)
|
||||
return -ENODEV;
|
||||
|
||||
if (source && strcmp(source, "auto") != 0) {
|
||||
DRM_DEBUG_DRIVER("Unknown CRC source %s for %s\n",
|
||||
source, crtc->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*values_cnt = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs ltdc_crtc_funcs = {
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
@ -1091,6 +1168,20 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_funcs ltdc_crtc_with_crc_support_funcs = {
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.reset = drm_atomic_helper_crtc_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.enable_vblank = ltdc_crtc_enable_vblank,
|
||||
.disable_vblank = ltdc_crtc_disable_vblank,
|
||||
.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
|
||||
.set_crc_source = ltdc_crtc_set_crc_source,
|
||||
.verify_crc_source = ltdc_crtc_verify_crc_source,
|
||||
};
|
||||
|
||||
/*
|
||||
* DRM_PLANE
|
||||
*/
|
||||
@ -1478,8 +1569,13 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
|
||||
|
||||
drm_plane_create_zpos_immutable_property(primary, 0);
|
||||
|
||||
ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
|
||||
<dc_crtc_funcs, NULL);
|
||||
/* Init CRTC according to its hardware features */
|
||||
if (ldev->caps.crc)
|
||||
ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
|
||||
<dc_crtc_with_crc_support_funcs, NULL);
|
||||
else
|
||||
ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
|
||||
<dc_crtc_funcs, NULL);
|
||||
if (ret) {
|
||||
DRM_ERROR("Can not initialize CRTC\n");
|
||||
goto cleanup;
|
||||
@ -1629,6 +1725,7 @@ static int ltdc_get_caps(struct drm_device *ddev)
|
||||
ldev->caps.ycbcr_input = false;
|
||||
ldev->caps.ycbcr_output = false;
|
||||
ldev->caps.plane_reg_shadow = false;
|
||||
ldev->caps.crc = false;
|
||||
break;
|
||||
case HWVER_20101:
|
||||
ldev->caps.layer_ofs = LAY_OFS_0;
|
||||
@ -1643,6 +1740,7 @@ static int ltdc_get_caps(struct drm_device *ddev)
|
||||
ldev->caps.ycbcr_input = false;
|
||||
ldev->caps.ycbcr_output = false;
|
||||
ldev->caps.plane_reg_shadow = false;
|
||||
ldev->caps.crc = false;
|
||||
break;
|
||||
case HWVER_40100:
|
||||
ldev->caps.layer_ofs = LAY_OFS_1;
|
||||
@ -1657,6 +1755,7 @@ static int ltdc_get_caps(struct drm_device *ddev)
|
||||
ldev->caps.ycbcr_input = true;
|
||||
ldev->caps.ycbcr_output = true;
|
||||
ldev->caps.plane_reg_shadow = true;
|
||||
ldev->caps.crc = true;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
|
@ -27,6 +27,7 @@ struct ltdc_caps {
|
||||
bool ycbcr_input; /* ycbcr input converter supported */
|
||||
bool ycbcr_output; /* ycbcr output converter supported */
|
||||
bool plane_reg_shadow; /* plane shadow registers ability */
|
||||
bool crc; /* cyclic redundancy check supported */
|
||||
};
|
||||
|
||||
#define LTDC_MAX_LAYER 4
|
||||
@ -46,6 +47,8 @@ struct ltdc_device {
|
||||
u32 irq_status;
|
||||
struct fps_info plane_fpsi[LTDC_MAX_LAYER];
|
||||
struct drm_atomic_state *suspend_state;
|
||||
int crc_skip_count;
|
||||
bool crc_active;
|
||||
};
|
||||
|
||||
int ltdc_load(struct drm_device *ddev);
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
static void sun4i_backend_layer_reset(struct drm_plane *plane)
|
||||
{
|
||||
struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
|
||||
struct sun4i_layer_state *state;
|
||||
|
||||
if (plane->state) {
|
||||
@ -31,10 +30,8 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
|
||||
}
|
||||
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (state) {
|
||||
if (state)
|
||||
__drm_atomic_helper_plane_reset(plane, &state->state);
|
||||
plane->state->zpos = layer->id;
|
||||
}
|
||||
}
|
||||
|
||||
static struct drm_plane_state *
|
||||
@ -192,7 +189,8 @@ static const uint64_t sun4i_layer_modifiers[] = {
|
||||
|
||||
static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
||||
struct sun4i_backend *backend,
|
||||
enum drm_plane_type type)
|
||||
enum drm_plane_type type,
|
||||
unsigned int id)
|
||||
{
|
||||
const uint64_t *modifiers = sun4i_layer_modifiers;
|
||||
const uint32_t *formats = sun4i_layer_formats;
|
||||
@ -204,6 +202,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
||||
if (!layer)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
layer->id = id;
|
||||
layer->backend = backend;
|
||||
|
||||
if (IS_ERR_OR_NULL(backend->frontend)) {
|
||||
@ -226,8 +225,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
||||
&sun4i_backend_layer_helper_funcs);
|
||||
|
||||
drm_plane_create_alpha_property(&layer->plane);
|
||||
drm_plane_create_zpos_property(&layer->plane, 0, 0,
|
||||
SUN4I_BACKEND_NUM_LAYERS - 1);
|
||||
drm_plane_create_zpos_property(&layer->plane, layer->id,
|
||||
0, SUN4I_BACKEND_NUM_LAYERS - 1);
|
||||
|
||||
return layer;
|
||||
}
|
||||
@ -249,14 +248,13 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
|
||||
enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
|
||||
struct sun4i_layer *layer;
|
||||
|
||||
layer = sun4i_layer_init_one(drm, backend, type);
|
||||
layer = sun4i_layer_init_one(drm, backend, type, i);
|
||||
if (IS_ERR(layer)) {
|
||||
dev_err(drm->dev, "Couldn't initialize %s plane\n",
|
||||
i ? "overlay" : "primary");
|
||||
return ERR_CAST(layer);
|
||||
}
|
||||
|
||||
layer->id = i;
|
||||
planes[i] = &layer->plane;
|
||||
}
|
||||
|
||||
|
@ -549,6 +549,15 @@ static void drm_dp_link_get_adjustments(struct drm_dp_link *link,
|
||||
{
|
||||
struct drm_dp_link_train_set *adjust = &link->train.adjust;
|
||||
unsigned int i;
|
||||
u8 post_cursor;
|
||||
int err;
|
||||
|
||||
err = drm_dp_dpcd_read(link->aux, DP_ADJUST_REQUEST_POST_CURSOR2,
|
||||
&post_cursor, sizeof(post_cursor));
|
||||
if (err < 0) {
|
||||
DRM_ERROR("failed to read post_cursor2: %d\n", err);
|
||||
post_cursor = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < link->lanes; i++) {
|
||||
adjust->voltage_swing[i] =
|
||||
@ -560,7 +569,7 @@ static void drm_dp_link_get_adjustments(struct drm_dp_link *link,
|
||||
DP_TRAIN_PRE_EMPHASIS_SHIFT;
|
||||
|
||||
adjust->post_cursor[i] =
|
||||
drm_dp_get_adjust_request_post_cursor(status, i);
|
||||
(post_cursor >> (i << 1)) & 0x3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,21 @@ config DRM_GM12U320
|
||||
This is a KMS driver for projectors which use the GM12U320 chipset
|
||||
for video transfer over USB2/3, such as the Acer C120 mini projector.
|
||||
|
||||
config DRM_PANEL_MIPI_DBI
|
||||
tristate "DRM support for MIPI DBI compatible panels"
|
||||
depends on DRM && SPI
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_MIPI_DBI
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select VIDEOMODE_HELPERS
|
||||
help
|
||||
Say Y here if you want to enable support for MIPI DBI compatible
|
||||
panels. The controller command setup can be provided using a
|
||||
firmware file. For more information see
|
||||
https://github.com/notro/panel-mipi-dbi/wiki.
|
||||
To compile this driver as a module, choose M here.
|
||||
|
||||
config DRM_SIMPLEDRM
|
||||
tristate "Simple framebuffer driver"
|
||||
depends on DRM && MMU
|
||||
|
@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
|
||||
obj-$(CONFIG_DRM_BOCHS) += bochs.o
|
||||
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
|
||||
obj-$(CONFIG_DRM_GM12U320) += gm12u320.o
|
||||
obj-$(CONFIG_DRM_PANEL_MIPI_DBI) += panel-mipi-dbi.o
|
||||
obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o
|
||||
obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o
|
||||
obj-$(CONFIG_TINYDRM_ILI9163) += ili9163.o
|
||||
|
398
drivers/gpu/drm/tiny/panel-mipi-dbi.c
Normal file
398
drivers/gpu/drm/tiny/panel-mipi-dbi.c
Normal file
@ -0,0 +1,398 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DRM driver for MIPI DBI compatible display panels
|
||||
*
|
||||
* Copyright 2022 Noralf Trønnes
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_mipi_dbi.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_modeset_helper.h>
|
||||
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
static const u8 panel_mipi_dbi_magic[15] = { 'M', 'I', 'P', 'I', ' ', 'D', 'B', 'I',
|
||||
0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
/*
|
||||
* The display controller configuration is stored in a firmware file.
|
||||
* The Device Tree 'compatible' property value with a '.bin' suffix is passed
|
||||
* to request_firmware() to fetch this file.
|
||||
*/
|
||||
struct panel_mipi_dbi_config {
|
||||
/* Magic string: panel_mipi_dbi_magic */
|
||||
u8 magic[15];
|
||||
|
||||
/* Config file format version */
|
||||
u8 file_format_version;
|
||||
|
||||
/*
|
||||
* MIPI commands to execute when the display pipeline is enabled.
|
||||
* This is used to configure the display controller.
|
||||
*
|
||||
* The commands are stored in a byte array with the format:
|
||||
* command, num_parameters, [ parameter, ...], command, ...
|
||||
*
|
||||
* Some commands require a pause before the next command can be received.
|
||||
* Inserting a delay in the command sequence is done by using the NOP command with one
|
||||
* parameter: delay in miliseconds (the No Operation command is part of the MIPI Display
|
||||
* Command Set where it has no parameters).
|
||||
*
|
||||
* Example:
|
||||
* command 0x11
|
||||
* sleep 120ms
|
||||
* command 0xb1 parameters 0x01, 0x2c, 0x2d
|
||||
* command 0x29
|
||||
*
|
||||
* Byte sequence:
|
||||
* 0x11 0x00
|
||||
* 0x00 0x01 0x78
|
||||
* 0xb1 0x03 0x01 0x2c 0x2d
|
||||
* 0x29 0x00
|
||||
*/
|
||||
u8 commands[];
|
||||
};
|
||||
|
||||
struct panel_mipi_dbi_commands {
|
||||
const u8 *buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static struct panel_mipi_dbi_commands *
|
||||
panel_mipi_dbi_check_commands(struct device *dev, const struct firmware *fw)
|
||||
{
|
||||
const struct panel_mipi_dbi_config *config = (struct panel_mipi_dbi_config *)fw->data;
|
||||
struct panel_mipi_dbi_commands *commands;
|
||||
size_t size = fw->size, commands_len;
|
||||
unsigned int i = 0;
|
||||
|
||||
if (size < sizeof(*config) + 2) { /* At least 1 command */
|
||||
dev_err(dev, "config: file size=%zu is too small\n", size);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (memcmp(config->magic, panel_mipi_dbi_magic, sizeof(config->magic))) {
|
||||
dev_err(dev, "config: Bad magic: %15ph\n", config->magic);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (config->file_format_version != 1) {
|
||||
dev_err(dev, "config: version=%u is not supported\n", config->file_format_version);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
drm_dev_dbg(dev, DRM_UT_DRIVER, "size=%zu version=%u\n", size, config->file_format_version);
|
||||
|
||||
commands_len = size - sizeof(*config);
|
||||
|
||||
while ((i + 1) < commands_len) {
|
||||
u8 command = config->commands[i++];
|
||||
u8 num_parameters = config->commands[i++];
|
||||
const u8 *parameters = &config->commands[i];
|
||||
|
||||
i += num_parameters;
|
||||
if (i > commands_len) {
|
||||
dev_err(dev, "config: command=0x%02x num_parameters=%u overflows\n",
|
||||
command, num_parameters);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (command == 0x00 && num_parameters == 1)
|
||||
drm_dev_dbg(dev, DRM_UT_DRIVER, "sleep %ums\n", parameters[0]);
|
||||
else
|
||||
drm_dev_dbg(dev, DRM_UT_DRIVER, "command %02x %*ph\n",
|
||||
command, num_parameters, parameters);
|
||||
}
|
||||
|
||||
if (i != commands_len) {
|
||||
dev_err(dev, "config: malformed command array\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
commands = devm_kzalloc(dev, sizeof(*commands), GFP_KERNEL);
|
||||
if (!commands)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
commands->len = commands_len;
|
||||
commands->buf = devm_kmemdup(dev, config->commands, commands->len, GFP_KERNEL);
|
||||
if (!commands->buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
static struct panel_mipi_dbi_commands *panel_mipi_dbi_commands_from_fw(struct device *dev)
|
||||
{
|
||||
struct panel_mipi_dbi_commands *commands;
|
||||
const struct firmware *fw;
|
||||
const char *compatible;
|
||||
char fw_name[40];
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_string_index(dev->of_node, "compatible", 0, &compatible);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
snprintf(fw_name, sizeof(fw_name), "%s.bin", compatible);
|
||||
ret = request_firmware(&fw, fw_name, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "No config file found for compatible '%s' (error=%d)\n",
|
||||
compatible, ret);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
commands = panel_mipi_dbi_check_commands(dev, fw);
|
||||
release_firmware(fw);
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
static void panel_mipi_dbi_commands_execute(struct mipi_dbi *dbi,
|
||||
struct panel_mipi_dbi_commands *commands)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
if (!commands)
|
||||
return;
|
||||
|
||||
while (i < commands->len) {
|
||||
u8 command = commands->buf[i++];
|
||||
u8 num_parameters = commands->buf[i++];
|
||||
const u8 *parameters = &commands->buf[i];
|
||||
|
||||
if (command == 0x00 && num_parameters == 1)
|
||||
msleep(parameters[0]);
|
||||
else if (num_parameters)
|
||||
mipi_dbi_command_stackbuf(dbi, command, parameters, num_parameters);
|
||||
else
|
||||
mipi_dbi_command(dbi, command);
|
||||
|
||||
i += num_parameters;
|
||||
}
|
||||
}
|
||||
|
||||
static void panel_mipi_dbi_enable(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
|
||||
struct mipi_dbi *dbi = &dbidev->dbi;
|
||||
int ret, idx;
|
||||
|
||||
if (!drm_dev_enter(pipe->crtc.dev, &idx))
|
||||
return;
|
||||
|
||||
drm_dbg(pipe->crtc.dev, "\n");
|
||||
|
||||
ret = mipi_dbi_poweron_conditional_reset(dbidev);
|
||||
if (ret < 0)
|
||||
goto out_exit;
|
||||
if (!ret)
|
||||
panel_mipi_dbi_commands_execute(dbi, dbidev->driver_private);
|
||||
|
||||
mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
|
||||
out_exit:
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
static const struct drm_simple_display_pipe_funcs panel_mipi_dbi_pipe_funcs = {
|
||||
.enable = panel_mipi_dbi_enable,
|
||||
.disable = mipi_dbi_pipe_disable,
|
||||
.update = mipi_dbi_pipe_update,
|
||||
};
|
||||
|
||||
DEFINE_DRM_GEM_CMA_FOPS(panel_mipi_dbi_fops);
|
||||
|
||||
static const struct drm_driver panel_mipi_dbi_driver = {
|
||||
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
|
||||
.fops = &panel_mipi_dbi_fops,
|
||||
DRM_GEM_CMA_DRIVER_OPS_VMAP,
|
||||
.debugfs_init = mipi_dbi_debugfs_init,
|
||||
.name = "panel-mipi-dbi",
|
||||
.desc = "MIPI DBI compatible display panel",
|
||||
.date = "20220103",
|
||||
.major = 1,
|
||||
.minor = 0,
|
||||
};
|
||||
|
||||
static int panel_mipi_dbi_get_mode(struct mipi_dbi_dev *dbidev, struct drm_display_mode *mode)
|
||||
{
|
||||
struct device *dev = dbidev->drm.dev;
|
||||
u16 hback_porch, vback_porch;
|
||||
int ret;
|
||||
|
||||
ret = of_get_drm_panel_display_mode(dev->of_node, mode, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "%pOF: failed to get panel-timing (error=%d)\n", dev->of_node, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
hback_porch = mode->htotal - mode->hsync_end;
|
||||
vback_porch = mode->vtotal - mode->vsync_end;
|
||||
|
||||
/*
|
||||
* Make sure width and height are set and that only back porch and
|
||||
* pixelclock are set in the other timing values. Also check that
|
||||
* width and height don't exceed the 16-bit value specified by MIPI DCS.
|
||||
*/
|
||||
if (!mode->hdisplay || !mode->vdisplay || mode->flags ||
|
||||
mode->hsync_end > mode->hdisplay || (hback_porch + mode->hdisplay) > 0xffff ||
|
||||
mode->vsync_end > mode->vdisplay || (vback_porch + mode->vdisplay) > 0xffff) {
|
||||
dev_err(dev, "%pOF: panel-timing out of bounds\n", dev->of_node);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The driver doesn't use the pixel clock but it is mandatory so fake one if not set */
|
||||
if (!mode->clock)
|
||||
mode->clock = mode->htotal * mode->vtotal * 60 / 1000;
|
||||
|
||||
dbidev->top_offset = vback_porch;
|
||||
dbidev->left_offset = hback_porch;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panel_mipi_dbi_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct drm_display_mode mode;
|
||||
struct mipi_dbi_dev *dbidev;
|
||||
struct drm_device *drm;
|
||||
struct mipi_dbi *dbi;
|
||||
struct gpio_desc *dc;
|
||||
int ret;
|
||||
|
||||
dbidev = devm_drm_dev_alloc(dev, &panel_mipi_dbi_driver, struct mipi_dbi_dev, drm);
|
||||
if (IS_ERR(dbidev))
|
||||
return PTR_ERR(dbidev);
|
||||
|
||||
dbi = &dbidev->dbi;
|
||||
drm = &dbidev->drm;
|
||||
|
||||
ret = panel_mipi_dbi_get_mode(dbidev, &mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dbidev->regulator = devm_regulator_get(dev, "power");
|
||||
if (IS_ERR(dbidev->regulator))
|
||||
return dev_err_probe(dev, PTR_ERR(dbidev->regulator),
|
||||
"Failed to get regulator 'power'\n");
|
||||
|
||||
dbidev->backlight = devm_of_find_backlight(dev);
|
||||
if (IS_ERR(dbidev->backlight))
|
||||
return dev_err_probe(dev, PTR_ERR(dbidev->backlight), "Failed to get backlight\n");
|
||||
|
||||
dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(dbi->reset))
|
||||
return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n");
|
||||
|
||||
dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(dc))
|
||||
return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n");
|
||||
|
||||
ret = mipi_dbi_spi_init(spi, dbi, dc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (device_property_present(dev, "write-only"))
|
||||
dbi->read_commands = NULL;
|
||||
|
||||
dbidev->driver_private = panel_mipi_dbi_commands_from_fw(dev);
|
||||
if (IS_ERR(dbidev->driver_private))
|
||||
return PTR_ERR(dbidev->driver_private);
|
||||
|
||||
ret = mipi_dbi_dev_init(dbidev, &panel_mipi_dbi_pipe_funcs, &mode, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
ret = drm_dev_register(drm, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_set_drvdata(spi, drm);
|
||||
|
||||
drm_fbdev_generic_setup(drm, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panel_mipi_dbi_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct drm_device *drm = spi_get_drvdata(spi);
|
||||
|
||||
drm_dev_unplug(drm);
|
||||
drm_atomic_helper_shutdown(drm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void panel_mipi_dbi_spi_shutdown(struct spi_device *spi)
|
||||
{
|
||||
drm_atomic_helper_shutdown(spi_get_drvdata(spi));
|
||||
}
|
||||
|
||||
static int __maybe_unused panel_mipi_dbi_pm_suspend(struct device *dev)
|
||||
{
|
||||
return drm_mode_config_helper_suspend(dev_get_drvdata(dev));
|
||||
}
|
||||
|
||||
static int __maybe_unused panel_mipi_dbi_pm_resume(struct device *dev)
|
||||
{
|
||||
drm_mode_config_helper_resume(dev_get_drvdata(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops panel_mipi_dbi_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(panel_mipi_dbi_pm_suspend, panel_mipi_dbi_pm_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id panel_mipi_dbi_spi_of_match[] = {
|
||||
{ .compatible = "panel-mipi-dbi-spi" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, panel_mipi_dbi_spi_of_match);
|
||||
|
||||
static const struct spi_device_id panel_mipi_dbi_spi_id[] = {
|
||||
{ "panel-mipi-dbi-spi", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, panel_mipi_dbi_spi_id);
|
||||
|
||||
static struct spi_driver panel_mipi_dbi_spi_driver = {
|
||||
.driver = {
|
||||
.name = "panel-mipi-dbi-spi",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = panel_mipi_dbi_spi_of_match,
|
||||
.pm = &panel_mipi_dbi_pm_ops,
|
||||
},
|
||||
.id_table = panel_mipi_dbi_spi_id,
|
||||
.probe = panel_mipi_dbi_spi_probe,
|
||||
.remove = panel_mipi_dbi_spi_remove,
|
||||
.shutdown = panel_mipi_dbi_spi_shutdown,
|
||||
};
|
||||
module_spi_driver(panel_mipi_dbi_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MIPI DBI compatible display panel driver");
|
||||
MODULE_AUTHOR("Noralf Trønnes");
|
||||
MODULE_LICENSE("GPL");
|
@ -508,26 +508,6 @@ static void repaper_get_temperature(struct repaper_epd *epd)
|
||||
epd->factored_stage_time = epd->stage_time * factor10x / 10;
|
||||
}
|
||||
|
||||
static void repaper_gray8_to_mono_reversed(u8 *buf, u32 width, u32 height)
|
||||
{
|
||||
u8 *gray8 = buf, *mono = buf;
|
||||
int y, xb, i;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
for (xb = 0; xb < width / 8; xb++) {
|
||||
u8 byte = 0x00;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
int x = xb * 8 + i;
|
||||
|
||||
byte >>= 1;
|
||||
if (gray8[y * width + x] >> 7)
|
||||
byte |= BIT(7);
|
||||
}
|
||||
*mono++ = byte;
|
||||
}
|
||||
}
|
||||
|
||||
static int repaper_fb_dirty(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
@ -560,12 +540,10 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb)
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
drm_fb_xrgb8888_to_gray8(buf, 0, cma_obj->vaddr, fb, &clip);
|
||||
drm_fb_xrgb8888_to_mono_reversed(buf, 0, cma_obj->vaddr, fb, &clip);
|
||||
|
||||
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
|
||||
|
||||
repaper_gray8_to_mono_reversed(buf, fb->width, fb->height);
|
||||
|
||||
if (epd->partial) {
|
||||
repaper_frame_data_repeat(epd, buf, epd->current_frame,
|
||||
REPAPER_NORMAL);
|
||||
|
@ -810,6 +810,9 @@ static int simpledrm_device_init_modeset(struct simpledrm_device *sdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs);
|
||||
drm_connector_set_panel_orientation_with_quirk(connector,
|
||||
DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
|
||||
mode->hdisplay, mode->vdisplay);
|
||||
|
||||
formats = simpledrm_device_formats(sdev, &nformats);
|
||||
|
||||
|
@ -392,34 +392,24 @@ v3d_sched_init(struct v3d_dev *v3d)
|
||||
hw_jobs_limit, job_hang_limit,
|
||||
msecs_to_jiffies(hang_limit_ms), NULL,
|
||||
NULL, "v3d_bin", v3d->drm.dev);
|
||||
if (ret) {
|
||||
dev_err(v3d->drm.dev, "Failed to create bin scheduler: %d.", ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched,
|
||||
&v3d_render_sched_ops,
|
||||
hw_jobs_limit, job_hang_limit,
|
||||
msecs_to_jiffies(hang_limit_ms), NULL,
|
||||
NULL, "v3d_render", v3d->drm.dev);
|
||||
if (ret) {
|
||||
dev_err(v3d->drm.dev, "Failed to create render scheduler: %d.",
|
||||
ret);
|
||||
v3d_sched_fini(v3d);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = drm_sched_init(&v3d->queue[V3D_TFU].sched,
|
||||
&v3d_tfu_sched_ops,
|
||||
hw_jobs_limit, job_hang_limit,
|
||||
msecs_to_jiffies(hang_limit_ms), NULL,
|
||||
NULL, "v3d_tfu", v3d->drm.dev);
|
||||
if (ret) {
|
||||
dev_err(v3d->drm.dev, "Failed to create TFU scheduler: %d.",
|
||||
ret);
|
||||
v3d_sched_fini(v3d);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
if (v3d_has_csd(v3d)) {
|
||||
ret = drm_sched_init(&v3d->queue[V3D_CSD].sched,
|
||||
@ -427,27 +417,23 @@ v3d_sched_init(struct v3d_dev *v3d)
|
||||
hw_jobs_limit, job_hang_limit,
|
||||
msecs_to_jiffies(hang_limit_ms), NULL,
|
||||
NULL, "v3d_csd", v3d->drm.dev);
|
||||
if (ret) {
|
||||
dev_err(v3d->drm.dev, "Failed to create CSD scheduler: %d.",
|
||||
ret);
|
||||
v3d_sched_fini(v3d);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched,
|
||||
&v3d_cache_clean_sched_ops,
|
||||
hw_jobs_limit, job_hang_limit,
|
||||
msecs_to_jiffies(hang_limit_ms), NULL,
|
||||
NULL, "v3d_cache_clean", v3d->drm.dev);
|
||||
if (ret) {
|
||||
dev_err(v3d->drm.dev, "Failed to create CACHE_CLEAN scheduler: %d.",
|
||||
ret);
|
||||
v3d_sched_fini(v3d);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
v3d_sched_fini(v3d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -16,15 +16,15 @@
|
||||
* must be laid out exactly in the same format as the framebuffer. Yes I know
|
||||
* their are cards with hardware that coverts images of various depths to the
|
||||
* framebuffer depth. But not every card has this. All images must be rounded
|
||||
* up to the nearest byte. For example a bitmap 12 bits wide must be two
|
||||
* bytes width.
|
||||
* up to the nearest byte. For example a bitmap 12 bits wide must be two
|
||||
* bytes width.
|
||||
*
|
||||
* Tony:
|
||||
* Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds
|
||||
* Tony:
|
||||
* Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds
|
||||
* up the code significantly.
|
||||
*
|
||||
*
|
||||
* Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
|
||||
* still processed a bit at a time.
|
||||
* still processed a bit at a time.
|
||||
*
|
||||
* Also need to add code to deal with cards endians that are different than
|
||||
* the native cpu endians. I also need to deal with MSB position in the word.
|
||||
@ -72,8 +72,8 @@ static const u32 cfb_tab32[] = {
|
||||
#define FB_WRITEL fb_writel
|
||||
#define FB_READL fb_readl
|
||||
|
||||
static inline void color_imageblit(const struct fb_image *image,
|
||||
struct fb_info *p, u8 __iomem *dst1,
|
||||
static inline void color_imageblit(const struct fb_image *image,
|
||||
struct fb_info *p, u8 __iomem *dst1,
|
||||
u32 start_index,
|
||||
u32 pitch_index)
|
||||
{
|
||||
@ -92,7 +92,7 @@ static inline void color_imageblit(const struct fb_image *image,
|
||||
dst = (u32 __iomem *) dst1;
|
||||
shift = 0;
|
||||
val = 0;
|
||||
|
||||
|
||||
if (start_index) {
|
||||
u32 start_mask = ~fb_shifted_pixels_mask_u32(p,
|
||||
start_index, bswapmask);
|
||||
@ -109,8 +109,8 @@ static inline void color_imageblit(const struct fb_image *image,
|
||||
val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
|
||||
if (shift >= null_bits) {
|
||||
FB_WRITEL(val, dst++);
|
||||
|
||||
val = (shift == null_bits) ? 0 :
|
||||
|
||||
val = (shift == null_bits) ? 0 :
|
||||
FB_SHIFT_LOW(p, color, 32 - shift);
|
||||
}
|
||||
shift += bpp;
|
||||
@ -134,9 +134,9 @@ static inline void color_imageblit(const struct fb_image *image,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p,
|
||||
static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p,
|
||||
u8 __iomem *dst1, u32 fgcolor,
|
||||
u32 bgcolor,
|
||||
u32 bgcolor,
|
||||
u32 start_index,
|
||||
u32 pitch_index)
|
||||
{
|
||||
@ -172,7 +172,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
||||
l--;
|
||||
color = (*s & (1 << l)) ? fgcolor : bgcolor;
|
||||
val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask);
|
||||
|
||||
|
||||
/* Did the bitshift spill bits to the next long? */
|
||||
if (shift >= null_bits) {
|
||||
FB_WRITEL(val, dst++);
|
||||
@ -191,16 +191,16 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
||||
|
||||
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
|
||||
}
|
||||
|
||||
|
||||
dst1 += pitch;
|
||||
src += spitch;
|
||||
src += spitch;
|
||||
if (pitch_index) {
|
||||
dst2 += pitch;
|
||||
dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1));
|
||||
start_index += pitch_index;
|
||||
start_index &= 32 - 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,29 +212,35 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
||||
* fix->line_legth is divisible by 4;
|
||||
* beginning and end of a scanline is dword aligned
|
||||
*/
|
||||
static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p,
|
||||
u8 __iomem *dst1, u32 fgcolor,
|
||||
u32 bgcolor)
|
||||
static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p,
|
||||
u8 __iomem *dst1, u32 fgcolor,
|
||||
u32 bgcolor)
|
||||
{
|
||||
u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
|
||||
u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
|
||||
u32 bit_mask, end_mask, eorx, shift;
|
||||
u32 bit_mask, eorx;
|
||||
const char *s = image->data, *src;
|
||||
u32 __iomem *dst;
|
||||
const u32 *tab = NULL;
|
||||
size_t tablen;
|
||||
u32 colortab[16];
|
||||
int i, j, k;
|
||||
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
|
||||
tablen = 16;
|
||||
break;
|
||||
case 16:
|
||||
tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
|
||||
tablen = 4;
|
||||
break;
|
||||
case 32:
|
||||
default:
|
||||
tab = cfb_tab32;
|
||||
tablen = 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = ppw-1; i--; ) {
|
||||
@ -243,25 +249,52 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
|
||||
fgx |= fgcolor;
|
||||
bgx |= bgcolor;
|
||||
}
|
||||
|
||||
|
||||
bit_mask = (1 << ppw) - 1;
|
||||
eorx = fgx ^ bgx;
|
||||
k = image->width/ppw;
|
||||
|
||||
for (i = 0; i < tablen; ++i)
|
||||
colortab[i] = (tab[i] & eorx) ^ bgx;
|
||||
|
||||
for (i = image->height; i--; ) {
|
||||
dst = (u32 __iomem *) dst1, shift = 8; src = s;
|
||||
|
||||
for (j = k; j--; ) {
|
||||
shift -= ppw;
|
||||
end_mask = tab[(*src >> shift) & bit_mask];
|
||||
FB_WRITEL((end_mask & eorx)^bgx, dst++);
|
||||
if (!shift) { shift = 8; src++; }
|
||||
dst = (u32 __iomem *)dst1;
|
||||
src = s;
|
||||
|
||||
switch (ppw) {
|
||||
case 4: /* 8 bpp */
|
||||
for (j = k; j; j -= 2, ++src) {
|
||||
FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
|
||||
}
|
||||
break;
|
||||
case 2: /* 16 bpp */
|
||||
for (j = k; j; j -= 4, ++src) {
|
||||
FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 2) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
|
||||
}
|
||||
break;
|
||||
case 1: /* 32 bpp */
|
||||
for (j = k; j; j -= 8, ++src) {
|
||||
FB_WRITEL(colortab[(*src >> 7) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 6) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 5) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 4) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 3) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 2) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 1) & bit_mask], dst++);
|
||||
FB_WRITEL(colortab[(*src >> 0) & bit_mask], dst++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dst1 += p->fix.line_length;
|
||||
s += spitch;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
|
||||
{
|
||||
u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
|
||||
@ -292,13 +325,13 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
|
||||
} else {
|
||||
fgcolor = image->fg_color;
|
||||
bgcolor = image->bg_color;
|
||||
}
|
||||
|
||||
if (32 % bpp == 0 && !start_index && !pitch_index &&
|
||||
}
|
||||
|
||||
if (32 % bpp == 0 && !start_index && !pitch_index &&
|
||||
((width & (32/bpp-1)) == 0) &&
|
||||
bpp >= 8 && bpp <= 32)
|
||||
bpp >= 8 && bpp <= 32)
|
||||
fast_imageblit(image, p, dst1, fgcolor, bgcolor);
|
||||
else
|
||||
else
|
||||
slow_imageblit(image, p, dst1, fgcolor, bgcolor,
|
||||
start_index, pitch_index);
|
||||
} else
|
||||
|
@ -50,19 +50,9 @@ bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
|
||||
|
||||
/* Main chunk */
|
||||
n /= bits;
|
||||
while (n >= 8) {
|
||||
*dst++ = pat;
|
||||
*dst++ = pat;
|
||||
*dst++ = pat;
|
||||
*dst++ = pat;
|
||||
*dst++ = pat;
|
||||
*dst++ = pat;
|
||||
*dst++ = pat;
|
||||
*dst++ = pat;
|
||||
n -= 8;
|
||||
}
|
||||
while (n--)
|
||||
*dst++ = pat;
|
||||
memset_l(dst, pat, n);
|
||||
dst += n;
|
||||
|
||||
/* Trailing bits */
|
||||
if (last)
|
||||
*dst = comp(pat, *dst, last);
|
||||
|
@ -188,23 +188,29 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
|
||||
{
|
||||
u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
|
||||
u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
|
||||
u32 bit_mask, end_mask, eorx, shift;
|
||||
u32 bit_mask, eorx;
|
||||
const char *s = image->data, *src;
|
||||
u32 *dst;
|
||||
const u32 *tab = NULL;
|
||||
const u32 *tab;
|
||||
size_t tablen;
|
||||
u32 colortab[16];
|
||||
int i, j, k;
|
||||
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le;
|
||||
tablen = 16;
|
||||
break;
|
||||
case 16:
|
||||
tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
|
||||
tablen = 4;
|
||||
break;
|
||||
case 32:
|
||||
default:
|
||||
tab = cfb_tab32;
|
||||
tablen = 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = ppw-1; i--; ) {
|
||||
@ -218,19 +224,40 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
|
||||
eorx = fgx ^ bgx;
|
||||
k = image->width/ppw;
|
||||
|
||||
for (i = 0; i < tablen; ++i)
|
||||
colortab[i] = (tab[i] & eorx) ^ bgx;
|
||||
|
||||
for (i = image->height; i--; ) {
|
||||
dst = dst1;
|
||||
shift = 8;
|
||||
src = s;
|
||||
|
||||
for (j = k; j--; ) {
|
||||
shift -= ppw;
|
||||
end_mask = tab[(*src >> shift) & bit_mask];
|
||||
*dst++ = (end_mask & eorx) ^ bgx;
|
||||
if (!shift) {
|
||||
shift = 8;
|
||||
src++;
|
||||
switch (ppw) {
|
||||
case 4: /* 8 bpp */
|
||||
for (j = k; j; j -= 2, ++src) {
|
||||
*dst++ = colortab[(*src >> 4) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 0) & bit_mask];
|
||||
}
|
||||
break;
|
||||
case 2: /* 16 bpp */
|
||||
for (j = k; j; j -= 4, ++src) {
|
||||
*dst++ = colortab[(*src >> 6) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 4) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 2) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 0) & bit_mask];
|
||||
}
|
||||
break;
|
||||
case 1: /* 32 bpp */
|
||||
for (j = k; j; j -= 8, ++src) {
|
||||
*dst++ = colortab[(*src >> 7) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 6) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 5) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 4) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 3) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 2) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 1) & bit_mask];
|
||||
*dst++ = colortab[(*src >> 0) & bit_mask];
|
||||
}
|
||||
break;
|
||||
}
|
||||
dst1 += p->fix.line_length;
|
||||
s += spitch;
|
||||
|
@ -456,7 +456,7 @@ struct drm_panel;
|
||||
#define DP_FEC_CAPABILITY_1 0x091 /* 2.0 */
|
||||
|
||||
/* DP-HDMI2.1 PCON DSC ENCODER SUPPORT */
|
||||
#define DP_PCON_DSC_ENCODER_CAP_SIZE 0xC /* 0x9E - 0x92 */
|
||||
#define DP_PCON_DSC_ENCODER_CAP_SIZE 0xD /* 0x92 through 0x9E */
|
||||
#define DP_PCON_DSC_ENCODER 0x092
|
||||
# define DP_PCON_DSC_ENCODER_SUPPORTED (1 << 0)
|
||||
# define DP_PCON_DSC_PPS_ENC_OVERRIDE (1 << 1)
|
||||
@ -1530,8 +1530,6 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI
|
||||
int lane);
|
||||
u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane);
|
||||
u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
unsigned int lane);
|
||||
|
||||
#define DP_BRANCH_OUI_HEADER_SIZE 0xc
|
||||
#define DP_RECEIVER_CAP_SIZE 0xf
|
||||
|
@ -130,6 +130,14 @@ struct mipi_dbi_dev {
|
||||
* @dbi: MIPI DBI interface
|
||||
*/
|
||||
struct mipi_dbi dbi;
|
||||
|
||||
/**
|
||||
* @driver_private: Driver private data.
|
||||
* Necessary for drivers with private data since devm_drm_dev_alloc()
|
||||
* can't allocate structures that embed a structure which then again
|
||||
* embeds drm_device.
|
||||
*/
|
||||
void *driver_private;
|
||||
};
|
||||
|
||||
static inline struct mipi_dbi_dev *drm_to_mipi_dbi_dev(struct drm_device *drm)
|
||||
|
@ -98,6 +98,10 @@ struct drm_object_properties {
|
||||
* Hence atomic drivers should not use drm_object_property_set_value()
|
||||
* and drm_object_property_get_value() on mutable objects, i.e. those
|
||||
* without the DRM_MODE_PROP_IMMUTABLE flag set.
|
||||
*
|
||||
* For atomic drivers the default value of properties is stored in this
|
||||
* array, so drm_object_property_get_default_value can be used to
|
||||
* retrieve it.
|
||||
*/
|
||||
uint64_t values[DRM_OBJECT_MAX_PROPERTY];
|
||||
};
|
||||
@ -126,6 +130,9 @@ int drm_object_property_set_value(struct drm_mode_object *obj,
|
||||
int drm_object_property_get_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t *value);
|
||||
int drm_object_property_get_default_value(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
uint64_t *val);
|
||||
|
||||
void drm_object_attach_property(struct drm_mode_object *obj,
|
||||
struct drm_property *property,
|
||||
|
@ -466,6 +466,8 @@ void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags);
|
||||
int of_get_drm_display_mode(struct device_node *np,
|
||||
struct drm_display_mode *dmode, u32 *bus_flags,
|
||||
int index);
|
||||
int of_get_drm_panel_display_mode(struct device_node *np,
|
||||
struct drm_display_mode *dmode, u32 *bus_flags);
|
||||
#else
|
||||
static inline int of_get_drm_display_mode(struct device_node *np,
|
||||
struct drm_display_mode *dmode,
|
||||
@ -473,6 +475,12 @@ static inline int of_get_drm_display_mode(struct device_node *np,
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int of_get_drm_panel_display_mode(struct device_node *np,
|
||||
struct drm_display_mode *dmode, u32 *bus_flags)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void drm_mode_set_name(struct drm_display_mode *mode);
|
||||
|
Loading…
Reference in New Issue
Block a user