Merge tag 'drm-misc-next-2025-05-08' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v6.16-rc1:

Cross-subsystem Changes:
- Change vsprintf %p4cn to %p4chR, remove %p4cn.

Core Changes:
- Documentation updates (fb rendering, actual_brightness)

Driver Changes:
- Small fixes to appletbdrm, panthor, st7571-i2c, rockchip, renesas,
  panic handler, gpusvm, vkms, panel timings.
- Add AUO B140QAN08.H, BOE NE140WUM-N6S, CSW MNE007QS3-8, BOE TD4320 panels.
- Convert rk3066_hdmi to bridge driver.
- Improve HPD on anx7625.
- Speed up loading tegra firmware, and other small fixes to tegra & host1x.

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://lore.kernel.org/r/5428be12-fc08-4e28-8c5f-85d73b8a7e04@linux.intel.com
This commit is contained in:
Dave Airlie 2025-05-10 16:13:46 +10:00
commit f9fa012293
38 changed files with 717 additions and 312 deletions

View File

@ -26,7 +26,12 @@ Date: March 2006
KernelVersion: 2.6.17
Contact: Richard Purdie <rpurdie@rpsys.net>
Description:
Show the actual brightness by querying the hardware.
Show the actual brightness by querying the hardware. Due
to implementation differences in hardware this may not
match the value in 'brightness'. For example some hardware
may treat blanking differently or have custom power saving
features. Userspace should generally use the values in
'brightness' to make decisions.
Users: HAL
What: /sys/class/backlight/<backlight>/max_brightness

View File

@ -652,7 +652,7 @@ Generic FourCC code
-------------------
::
%p4c[hnlb] gP00 (0x67503030)
%p4c[h[R]lb] gP00 (0x67503030)
Print a generic FourCC code, as both ASCII characters and its numerical
value as hexadecimal.
@ -660,23 +660,23 @@ value as hexadecimal.
The generic FourCC code is always printed in the big-endian format,
the most significant byte first. This is the opposite of V4L/DRM FourCCs.
The additional ``h``, ``n``, ``l``, and ``b`` specifiers define what
The additional ``h``, ``hR``, ``l``, and ``b`` specifiers define what
endianness is used to load the stored bytes. The data might be interpreted
using the host byte order, network byte order, little-endian, or big-endian.
using the host, reversed host byte order, little-endian, or big-endian.
Passed by reference.
Examples for a little-endian machine, given &(u32)0x67503030::
%p4ch gP00 (0x67503030)
%p4cn 00Pg (0x30305067)
%p4chR 00Pg (0x30305067)
%p4cl gP00 (0x67503030)
%p4cb 00Pg (0x30305067)
Examples for a big-endian machine, given &(u32)0x67503030::
%p4ch gP00 (0x67503030)
%p4cn 00Pg (0x30305067)
%p4chR 00Pg (0x30305067)
%p4cl 00Pg (0x30305067)
%p4cb gP00 (0x67503030)

View File

@ -0,0 +1,65 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/boe,td4320.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: BOE TD4320 MIPI-DSI panels
maintainers:
- Barnabas Czeman <barnabas.czeman@mainlining.org>
description:
BOE TD4320 6.3" 1080x2340 panel found in Xiaomi Redmi Note 7 smartphone.
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- const: boe,td4320
reg:
maxItems: 1
iovcc-supply:
description: I/O voltage rail
vsn-supply:
description: Negative source voltage rail
vsp-supply:
description: Positive source voltage rail
required:
- compatible
- reg
- reset-gpios
- port
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "boe,td4320";
reg = <0>;
backlight = <&backlight>;
reset-gpios = <&tlmm 45 GPIO_ACTIVE_LOW>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
...

View File

@ -23,6 +23,7 @@ properties:
maxItems: 1
backlight: true
port: true
reset-gpios: true
iovcc-supply:
description: regulator that supplies the iovcc voltage

View File

@ -22,6 +22,7 @@ properties:
maxItems: 1
backlight: true
port: true
reset-gpios: true
iovcc-supply:
description: regulator that supplies the iovcc voltage

View File

@ -23,13 +23,11 @@ properties:
maxItems: 1
clocks:
minItems: 1
items:
- description: The HDMI controller main clock
- description: The HDMI PHY reference clock
clock-names:
minItems: 1
items:
- const: pclk
- const: ref
@ -58,6 +56,12 @@ properties:
- port@0
- port@1
rockchip,grf:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to GRF used for control the polarity of hsync/vsync of rk3036
HDMI.
required:
- compatible
- reg
@ -77,6 +81,8 @@ allOf:
const: rockchip,rk3036-inno-hdmi
then:
required:
- rockchip,grf
properties:
power-domains: false
@ -87,11 +93,6 @@ allOf:
const: rockchip,rk3128-inno-hdmi
then:
properties:
clocks:
minItems: 2
clock-names:
minItems: 2
required:
- power-domains
@ -106,10 +107,11 @@ examples:
compatible = "rockchip,rk3036-inno-hdmi";
reg = <0x20034000 0x4000>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_HDMI>;
clock-names = "pclk";
clocks = <&cru PCLK_HDMI>, <&cru SCLK_LCDC>;
clock-names = "pclk", "ref";
pinctrl-names = "default";
pinctrl-0 = <&hdmi_ctl>;
rockchip,grf = <&grf>;
#sound-dai-cells = <0>;
ports {

View File

@ -1257,10 +1257,10 @@ static void anx7625_power_on(struct anx7625_data *ctx)
usleep_range(11000, 12000);
/* Power on pin enable */
gpiod_set_value(ctx->pdata.gpio_p_on, 1);
gpiod_set_value_cansleep(ctx->pdata.gpio_p_on, 1);
usleep_range(10000, 11000);
/* Power reset pin enable */
gpiod_set_value(ctx->pdata.gpio_reset, 1);
gpiod_set_value_cansleep(ctx->pdata.gpio_reset, 1);
usleep_range(10000, 11000);
DRM_DEV_DEBUG_DRIVER(dev, "power on !\n");
@ -1280,9 +1280,9 @@ static void anx7625_power_standby(struct anx7625_data *ctx)
return;
}
gpiod_set_value(ctx->pdata.gpio_reset, 0);
gpiod_set_value_cansleep(ctx->pdata.gpio_reset, 0);
usleep_range(1000, 1100);
gpiod_set_value(ctx->pdata.gpio_p_on, 0);
gpiod_set_value_cansleep(ctx->pdata.gpio_p_on, 0);
usleep_range(1000, 1100);
ret = regulator_bulk_disable(ARRAY_SIZE(ctx->pdata.supplies),
@ -1814,9 +1814,6 @@ static enum drm_connector_status anx7625_sink_detect(struct anx7625_data *ctx)
DRM_DEV_DEBUG_DRIVER(dev, "sink detect\n");
if (ctx->pdata.panel_bridge)
return connector_status_connected;
return ctx->hpd_status ? connector_status_connected :
connector_status_disconnected;
}
@ -2475,6 +2472,22 @@ static const struct drm_edid *anx7625_bridge_edid_read(struct drm_bridge *bridge
return anx7625_edid_read(ctx);
}
static void anx7625_bridge_hpd_enable(struct drm_bridge *bridge)
{
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
struct device *dev = ctx->dev;
pm_runtime_get_sync(dev);
}
static void anx7625_bridge_hpd_disable(struct drm_bridge *bridge)
{
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
struct device *dev = ctx->dev;
pm_runtime_put_sync(dev);
}
static const struct drm_bridge_funcs anx7625_bridge_funcs = {
.attach = anx7625_bridge_attach,
.detach = anx7625_bridge_detach,
@ -2488,6 +2501,8 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = {
.atomic_reset = drm_atomic_helper_bridge_reset,
.detect = anx7625_bridge_detect,
.edid_read = anx7625_bridge_edid_read,
.hpd_enable = anx7625_bridge_hpd_enable,
.hpd_disable = anx7625_bridge_hpd_disable,
};
static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx,
@ -2585,9 +2600,8 @@ static int anx7625_link_bridge(struct drm_dp_aux *aux)
platform->bridge.of_node = dev->of_node;
if (!anx7625_of_panel_on_aux_bus(dev))
platform->bridge.ops |= DRM_BRIDGE_OP_EDID;
if (!platform->pdata.panel_bridge)
platform->bridge.ops |= DRM_BRIDGE_OP_HPD |
DRM_BRIDGE_OP_DETECT;
if (!platform->pdata.panel_bridge || !anx7625_of_panel_on_aux_bus(dev))
platform->bridge.ops |= DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_DETECT;
platform->bridge.type = platform->pdata.panel_bridge ?
DRM_MODE_CONNECTOR_eDP :
DRM_MODE_CONNECTOR_DisplayPort;

View File

@ -75,6 +75,12 @@
* the currently visible vertical area of the &drm_crtc.
* FB_ID:
* Mode object ID of the &drm_framebuffer this plane should scan out.
*
* When a KMS client is performing front-buffer rendering, it should set
* FB_ID to the same front-buffer FB on each atomic commit. This implies
* to the driver that it needs to re-read the same FB again. Otherwise
* drivers which do not employ continuously repeated scanout cycles might
* not update the screen.
* CRTC_ID:
* Mode object ID of the &drm_crtc this plane should be connected to.
*

View File

@ -1330,7 +1330,6 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
unsigned long num_dma_mapped;
unsigned int order = 0;
unsigned long *pfns;
struct page **pages;
int err = 0;
struct dev_pagemap *pagemap;
struct drm_pagemap *dpagemap;
@ -1369,7 +1368,6 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
if (err)
goto err_free;
pages = (struct page **)pfns;
map_pages:
/*
* Perform all dma mappings under the notifier lock to not
@ -1444,8 +1442,6 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
err = -EFAULT;
goto err_unmap;
}
pages[i] = page;
} else {
dma_addr_t addr;

View File

@ -366,8 +366,48 @@ fn iter(&self) -> SegmentIterator<'_> {
SegmentIterator {
segment: self,
offset: 0,
carry: 0,
carry_len: 0,
decfifo: Default::default(),
}
}
}
/// Max fifo size is 17 (max push) + 2 (max remaining)
const MAX_FIFO_SIZE: usize = 19;
/// A simple Decimal digit FIFO
#[derive(Default)]
struct DecFifo {
decimals: [u8; MAX_FIFO_SIZE],
len: usize,
}
impl DecFifo {
fn push(&mut self, data: u64, len: usize) {
let mut chunk = data;
for i in (0..self.len).rev() {
self.decimals[i + len] = self.decimals[i];
}
for i in 0..len {
self.decimals[i] = (chunk % 10) as u8;
chunk /= 10;
}
self.len += len;
}
/// Pop 3 decimal digits from the FIFO
fn pop3(&mut self) -> Option<(u16, usize)> {
if self.len == 0 {
None
} else {
let poplen = 3.min(self.len);
self.len -= poplen;
let mut out = 0;
let mut exp = 1;
for i in 0..poplen {
out += self.decimals[self.len + i] as u16 * exp;
exp *= 10;
}
Some((out, NUM_CHARS_BITS[poplen]))
}
}
}
@ -375,8 +415,7 @@ fn iter(&self) -> SegmentIterator<'_> {
struct SegmentIterator<'a> {
segment: &'a Segment<'a>,
offset: usize,
carry: u64,
carry_len: usize,
decfifo: DecFifo,
}
impl Iterator for SegmentIterator<'_> {
@ -394,31 +433,17 @@ fn next(&mut self) -> Option<Self::Item> {
}
}
Segment::Numeric(data) => {
if self.carry_len < 3 && self.offset < data.len() {
// If there are less than 3 decimal digits in the carry,
// take the next 7 bytes of input, and add them to the carry.
if self.decfifo.len < 3 && self.offset < data.len() {
// If there are less than 3 decimal digits in the fifo,
// take the next 7 bytes of input, and push them to the fifo.
let mut buf = [0u8; 8];
let len = 7.min(data.len() - self.offset);
buf[..len].copy_from_slice(&data[self.offset..self.offset + len]);
let chunk = u64::from_le_bytes(buf);
let pow = u64::pow(10, BYTES_TO_DIGITS[len] as u32);
self.carry = chunk + self.carry * pow;
self.decfifo.push(chunk, BYTES_TO_DIGITS[len]);
self.offset += len;
self.carry_len += BYTES_TO_DIGITS[len];
}
match self.carry_len {
0 => None,
len => {
// take the next 3 decimal digits of the carry
// and return 10bits of numeric data.
let out_len = 3.min(len);
self.carry_len -= out_len;
let pow = u64::pow(10, self.carry_len as u32);
let out = (self.carry / pow) as u16;
self.carry %= pow;
Some((out, NUM_CHARS_BITS[out_len]))
}
}
self.decfifo.pop3()
}
}
}

View File

@ -67,6 +67,15 @@ config DRM_PANEL_BOE_HIMAX8279D
24 bit RGB per pixel. It provides a MIPI DSI interface to
the host and has a built-in LED backlight.
config DRM_PANEL_BOE_TD4320
tristate "BOE TD4320 DSI 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 BOE TD4320 1080x2340
video mode panel found in Xiaomi Redmi Note 7 smartphones.
config DRM_PANEL_BOE_TH101MB31UIG002_28A
tristate "Boe TH101MB31UIG002-28A panel"
depends on OF

View File

@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.
obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o
obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o
obj-$(CONFIG_DRM_PANEL_BOE_TD4320) += panel-boe-td4320.o
obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_LL2) += panel-boe-tv101wum-ll2.o
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o

View File

@ -0,0 +1,247 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2024 Barnabas Czeman <barnabas.czeman@mainlining.org>
// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
// Copyright (c) 2013, The Linux Foundation. All rights reserved.
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
struct boe_td4320 {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct regulator_bulk_data *supplies;
struct gpio_desc *reset_gpio;
};
static const struct regulator_bulk_data boe_td4320_supplies[] = {
{ .supply = "iovcc" },
{ .supply = "vsn" },
{ .supply = "vsp" },
};
static inline struct boe_td4320 *to_boe_td4320(struct drm_panel *panel)
{
return container_of(panel, struct boe_td4320, panel);
}
static void boe_td4320_reset(struct boe_td4320 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(1000, 2000);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
usleep_range(5000, 6000);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
msleep(30);
}
static int boe_td4320_on(struct boe_td4320 *ctx)
{
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x04);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8,
0x19, 0x55, 0x00, 0xbe, 0x00, 0x00,
0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9,
0x4d, 0x55, 0x05, 0xe6, 0x00, 0x02,
0x03);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba,
0x9b, 0x5b, 0x07, 0xe6, 0x00, 0x13,
0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9,
0x44, 0x3f, 0x00, 0x8d, 0xbf);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce,
0x5d, 0x00, 0x0f, 0x1f, 0x2f, 0x3f,
0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f,
0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
0x04, 0x00, 0x02, 0x02, 0x42, 0x01,
0x69, 0x5a, 0x40, 0x40, 0x00, 0x00,
0x04, 0xfa, 0x00);
mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x00b8);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
0x2c);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x03);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x00);
mipi_dsi_msleep(&dsi_ctx, 96);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x00);
mipi_dsi_msleep(&dsi_ctx, 20);
return dsi_ctx.accum_err;
}
static int boe_td4320_off(struct boe_td4320 *ctx)
{
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 20);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
return dsi_ctx.accum_err;
}
static int boe_td4320_prepare(struct drm_panel *panel)
{
struct boe_td4320 *ctx = to_boe_td4320(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(boe_td4320_supplies), ctx->supplies);
if (ret < 0) {
dev_err(dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
boe_td4320_reset(ctx);
ret = boe_td4320_on(ctx);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(boe_td4320_supplies), ctx->supplies);
return ret;
}
return 0;
}
static int boe_td4320_unprepare(struct drm_panel *panel)
{
struct boe_td4320 *ctx = to_boe_td4320(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
ret = boe_td4320_off(ctx);
if (ret < 0)
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(boe_td4320_supplies), ctx->supplies);
return 0;
}
static const struct drm_display_mode boe_td4320_mode = {
.clock = (1080 + 86 + 2 + 100) * (2340 + 4 + 4 + 60) * 60 / 1000,
.hdisplay = 1080,
.hsync_start = 1080 + 86,
.hsync_end = 1080 + 86 + 2,
.htotal = 1080 + 86 + 2 + 100,
.vdisplay = 2340,
.vsync_start = 2340 + 4,
.vsync_end = 2340 + 4 + 4,
.vtotal = 2340 + 4 + 4 + 60,
.width_mm = 67,
.height_mm = 145,
.type = DRM_MODE_TYPE_DRIVER,
};
static int boe_td4320_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
return drm_connector_helper_get_modes_fixed(connector, &boe_td4320_mode);
}
static const struct drm_panel_funcs boe_td4320_panel_funcs = {
.prepare = boe_td4320_prepare,
.unprepare = boe_td4320_unprepare,
.get_modes = boe_td4320_get_modes,
};
static int boe_td4320_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct boe_td4320 *ctx;
int ret;
ctx = devm_drm_panel_alloc(dev, struct boe_td4320, panel,
&boe_td4320_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
ret = devm_regulator_bulk_get_const(dev,
ARRAY_SIZE(boe_td4320_supplies),
boe_td4320_supplies,
&ctx->supplies);
if (ret < 0)
return ret;
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->reset_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
ctx->dsi = dsi;
mipi_dsi_set_drvdata(dsi, ctx);
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_CLOCK_NON_CONTINUOUS;
ctx->panel.prepare_prev_first = true;
ret = drm_panel_of_backlight(&ctx->panel);
if (ret)
return dev_err_probe(dev, ret, "Failed to get backlight\n");
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
drm_panel_remove(&ctx->panel);
return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
}
return 0;
}
static void boe_td4320_remove(struct mipi_dsi_device *dsi)
{
struct boe_td4320 *ctx = mipi_dsi_get_drvdata(dsi);
int ret;
ret = mipi_dsi_detach(dsi);
if (ret < 0)
dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
}
static const struct of_device_id boe_td4320_of_match[] = {
{ .compatible = "boe,td4320" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, boe_td4320_of_match);
static struct mipi_dsi_driver boe_td4320_driver = {
.probe = boe_td4320_probe,
.remove = boe_td4320_remove,
.driver = {
.name = "panel-boe-td4320",
.of_match_table = boe_td4320_of_match,
},
};
module_mipi_dsi_driver(boe_td4320_driver);
MODULE_AUTHOR("Barnabas Czeman <barnabas.czeman@mainlining.org>");
MODULE_DESCRIPTION("DRM driver for boe td4320 fhdplus video mode dsi panel");
MODULE_LICENSE("GPL");

View File

@ -1762,6 +1762,13 @@ static const struct panel_delay delay_80_500_e50 = {
.enable = 50,
};
static const struct panel_delay delay_80_500_e80_p2e200 = {
.hpd_absent = 80,
.unprepare = 500,
.enable = 80,
.prepare_to_enable = 200,
};
static const struct panel_delay delay_100_500_e200 = {
.hpd_absent = 100,
.unprepare = 500,
@ -1877,6 +1884,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0xa199, &delay_200_500_e50, "B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xa7b3, &delay_200_500_e50, "B140UAN04.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xc4b4, &delay_200_500_e50, "B116XAT04.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xc9a8, &delay_200_500_e50, "B140QAN08.H"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xd497, &delay_200_500_e50, "B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"),
@ -1937,6 +1945,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c93, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d73, &delay_200_500_e80, "NE140WUM-N6S"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"),
@ -1972,6 +1981,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1103, &delay_200_500_e80_d50, "MNB601LS1-3"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1104, &delay_200_500_e50, "MNB601LS1-4"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1448, &delay_200_500_e50, "MNE007QS3-7"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1457, &delay_80_500_e80_p2e200, "MNE007QS3-8"),
EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"),

View File

@ -1026,27 +1026,28 @@ static const struct panel_desc auo_g070vvn01 = {
},
};
static const struct drm_display_mode auo_g101evn010_mode = {
.clock = 68930,
.hdisplay = 1280,
.hsync_start = 1280 + 82,
.hsync_end = 1280 + 82 + 2,
.htotal = 1280 + 82 + 2 + 84,
.vdisplay = 800,
.vsync_start = 800 + 8,
.vsync_end = 800 + 8 + 2,
.vtotal = 800 + 8 + 2 + 6,
static const struct display_timing auo_g101evn010_timing = {
.pixelclock = { 64000000, 68930000, 85000000 },
.hactive = { 1280, 1280, 1280 },
.hfront_porch = { 8, 64, 256 },
.hback_porch = { 8, 64, 256 },
.hsync_len = { 40, 168, 767 },
.vactive = { 800, 800, 800 },
.vfront_porch = { 4, 8, 100 },
.vback_porch = { 4, 8, 100 },
.vsync_len = { 8, 16, 223 },
};
static const struct panel_desc auo_g101evn010 = {
.modes = &auo_g101evn010_mode,
.num_modes = 1,
.timings = &auo_g101evn010_timing,
.num_timings = 1,
.bpc = 6,
.size = {
.width = 216,
.height = 135,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};

View File

@ -42,11 +42,16 @@ static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo)
mutex_unlock(&ptdev->gems.lock);
}
static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags)
{
bo->debugfs.flags = usage_flags | PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED;
}
#else
static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev,
struct panthor_gem_object *bo)
{}
static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {}
static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {}
#endif
static void panthor_gem_free_object(struct drm_gem_object *obj)

View File

@ -212,14 +212,6 @@ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo);
#ifdef CONFIG_DEBUG_FS
void panthor_gem_debugfs_print_bos(struct panthor_device *pfdev,
struct seq_file *m);
static inline void
panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags)
{
bo->debugfs.flags = usage_flags | PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED;
}
#else
void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {};
#endif
#endif /* __PANTHOR_GEM_H__ */

View File

@ -32,11 +32,6 @@ struct rcar_cmm {
} lut;
};
static inline int rcar_cmm_read(struct rcar_cmm *rcmm, u32 reg)
{
return ioread32(rcmm->base + reg);
}
static inline void rcar_cmm_write(struct rcar_cmm *rcmm, u32 reg, u32 data)
{
iowrite32(data, rcmm->base + reg);

View File

@ -705,7 +705,7 @@ static int rcar_du_vsps_init(struct rcar_du_device *rcdu)
ret = of_parse_phandle_with_fixed_args(np, vsps_prop_name,
cells, i, &args);
if (ret < 0)
goto error;
goto done;
/*
* Add the VSP to the list or update the corresponding existing
@ -743,13 +743,11 @@ static int rcar_du_vsps_init(struct rcar_du_device *rcdu)
vsp->dev = rcdu;
ret = rcar_du_vsp_init(vsp, vsps[i].np, vsps[i].crtcs_mask);
if (ret < 0)
goto error;
if (ret)
goto done;
}
return 0;
error:
done:
for (i = 0; i < ARRAY_SIZE(vsps); ++i)
of_node_put(vsps[i].np);

View File

@ -2,6 +2,7 @@
config DRM_ROCKCHIP
tristate "DRM Support for Rockchip"
depends on DRM && ROCKCHIP_IOMMU
depends on OF
select DRM_CLIENT_SELECTION
select DRM_GEM_DMA_HELPER
select DRM_KMS_HELPER

View File

@ -10,10 +10,12 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/hdmi.h>
#include <linux/mfd/syscon.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@ -29,8 +31,19 @@
#include "inno_hdmi.h"
#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16)
#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
#define RK3036_GRF_SOC_CON2 0x148
#define RK3036_HDMI_PHSYNC BIT(4)
#define RK3036_HDMI_PVSYNC BIT(5)
enum inno_hdmi_dev_type {
RK3036_HDMI,
RK3128_HDMI,
};
struct inno_hdmi_phy_config {
unsigned long pixelclock;
u8 pre_emphasis;
@ -38,6 +51,7 @@ struct inno_hdmi_phy_config {
};
struct inno_hdmi_variant {
enum inno_hdmi_dev_type dev_type;
struct inno_hdmi_phy_config *phy_configs;
struct inno_hdmi_phy_config *default_phy_config;
};
@ -58,6 +72,7 @@ struct inno_hdmi {
struct clk *pclk;
struct clk *refclk;
void __iomem *regs;
struct regmap *grf;
struct drm_connector connector;
struct rockchip_encoder encoder;
@ -374,7 +389,15 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
struct drm_display_mode *mode)
{
int value;
int value, psync;
if (hdmi->variant->dev_type == RK3036_HDMI) {
psync = mode->flags & DRM_MODE_FLAG_PHSYNC ? RK3036_HDMI_PHSYNC : 0;
value = HIWORD_UPDATE(psync, RK3036_HDMI_PHSYNC);
psync = mode->flags & DRM_MODE_FLAG_PVSYNC ? RK3036_HDMI_PVSYNC : 0;
value |= HIWORD_UPDATE(psync, RK3036_HDMI_PVSYNC);
regmap_write(hdmi->grf, RK3036_GRF_SOC_CON2, value);
}
/* Set detail external video timing polarity and interlace mode */
value = v_EXTERANL_VIDEO(1);
@ -885,32 +908,34 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
return PTR_ERR(hdmi->regs);
hdmi->pclk = devm_clk_get(hdmi->dev, "pclk");
if (IS_ERR(hdmi->pclk)) {
DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n");
return PTR_ERR(hdmi->pclk);
}
if (IS_ERR(hdmi->pclk))
return dev_err_probe(dev, PTR_ERR(hdmi->pclk), "Unable to get HDMI pclk\n");
ret = clk_prepare_enable(hdmi->pclk);
if (ret) {
DRM_DEV_ERROR(hdmi->dev,
"Cannot enable HDMI pclk clock: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Cannot enable HDMI pclk: %d\n", ret);
hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref");
if (IS_ERR(hdmi->refclk)) {
DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n");
ret = PTR_ERR(hdmi->refclk);
ret = dev_err_probe(dev, PTR_ERR(hdmi->refclk), "Unable to get HDMI refclk\n");
goto err_disable_pclk;
}
ret = clk_prepare_enable(hdmi->refclk);
if (ret) {
DRM_DEV_ERROR(hdmi->dev,
"Cannot enable HDMI reference clock: %d\n", ret);
ret = dev_err_probe(dev, ret, "Cannot enable HDMI refclk: %d\n", ret);
goto err_disable_pclk;
}
if (hdmi->variant->dev_type == RK3036_HDMI) {
hdmi->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
if (IS_ERR(hdmi->grf)) {
ret = dev_err_probe(dev, PTR_ERR(hdmi->grf),
"Unable to get rockchip,grf\n");
goto err_disable_clk;
}
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
@ -995,11 +1020,13 @@ static void inno_hdmi_remove(struct platform_device *pdev)
}
static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = {
.dev_type = RK3036_HDMI,
.phy_configs = rk3036_hdmi_phy_configs,
.default_phy_config = &rk3036_hdmi_phy_configs[1],
};
static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = {
.dev_type = RK3128_HDMI,
.phy_configs = rk3128_hdmi_phy_configs,
.default_phy_config = &rk3128_hdmi_phy_configs[1],
};

View File

@ -5,6 +5,9 @@
*/
#include <drm/drm_atomic.h>
#include <drm/drm_bridge_connector.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
@ -46,27 +49,20 @@ struct rk3066_hdmi {
struct clk *hclk;
void __iomem *regs;
struct drm_connector connector;
struct drm_bridge bridge;
struct drm_connector *connector;
struct rockchip_encoder encoder;
struct rk3066_hdmi_i2c *i2c;
struct i2c_adapter *ddc;
unsigned int tmdsclk;
struct hdmi_data_info hdmi_data;
};
static struct rk3066_hdmi *encoder_to_rk3066_hdmi(struct drm_encoder *encoder)
static struct rk3066_hdmi *bridge_to_rk3066_hdmi(struct drm_bridge *bridge)
{
struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
return container_of(rkencoder, struct rk3066_hdmi, encoder);
}
static struct rk3066_hdmi *connector_to_rk3066_hdmi(struct drm_connector *connector)
{
return container_of(connector, struct rk3066_hdmi, connector);
return container_of(bridge, struct rk3066_hdmi, bridge);
}
static inline u8 hdmi_readb(struct rk3066_hdmi *hdmi, u16 offset)
@ -161,57 +157,40 @@ static void rk3066_hdmi_set_power_mode(struct rk3066_hdmi *hdmi, int mode)
hdmi->tmdsclk = DEFAULT_PLLA_RATE;
}
static int
rk3066_hdmi_upload_frame(struct rk3066_hdmi *hdmi, int setup_rc,
union hdmi_infoframe *frame, u32 frame_index,
u32 mask, u32 disable, u32 enable)
static int rk3066_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
enum hdmi_infoframe_type type)
{
if (mask)
hdmi_modb(hdmi, HDMI_CP_AUTO_SEND_CTRL, mask, disable);
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, frame_index);
if (setup_rc >= 0) {
u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
ssize_t rc, i;
rc = hdmi_infoframe_pack(frame, packed_frame,
sizeof(packed_frame));
if (rc < 0)
return rc;
for (i = 0; i < rc; i++)
hdmi_writeb(hdmi, HDMI_CP_BUF_ACC_HB0 + i * 4,
packed_frame[i]);
if (mask)
hdmi_modb(hdmi, HDMI_CP_AUTO_SEND_CTRL, mask, enable);
if (type != HDMI_INFOFRAME_TYPE_AVI) {
drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type);
return 0;
}
return setup_rc;
hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, HDMI_INFOFRAME_AVI);
return 0;
}
static int rk3066_hdmi_config_avi(struct rk3066_hdmi *hdmi,
struct drm_display_mode *mode)
static int
rk3066_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
enum hdmi_infoframe_type type,
const u8 *buffer, size_t len)
{
union hdmi_infoframe frame;
int rc;
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
ssize_t i;
rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
&hdmi->connector, mode);
if (type != HDMI_INFOFRAME_TYPE_AVI) {
drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type);
return 0;
}
if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444)
frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422)
frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
else
frame.avi.colorspace = HDMI_COLORSPACE_RGB;
rk3066_hdmi_bridge_clear_infoframe(bridge, type);
frame.avi.colorimetry = hdmi->hdmi_data.colorimetry;
frame.avi.scan_mode = HDMI_SCAN_MODE_NONE;
for (i = 0; i < len; i++)
hdmi_writeb(hdmi, HDMI_CP_BUF_ACC_HB0 + i * 4, buffer[i]);
return rk3066_hdmi_upload_frame(hdmi, rc, &frame,
HDMI_INFOFRAME_AVI, 0, 0, 0);
return 0;
}
static int rk3066_hdmi_config_video_timing(struct rk3066_hdmi *hdmi,
@ -324,9 +303,27 @@ static void rk3066_hdmi_config_phy(struct rk3066_hdmi *hdmi)
}
static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
struct drm_display_mode *mode)
struct drm_atomic_state *state)
{
struct drm_display_info *display = &hdmi->connector.display_info;
struct drm_bridge *bridge = &hdmi->bridge;
struct drm_connector *connector;
struct drm_display_info *display;
struct drm_display_mode *mode;
struct drm_connector_state *new_conn_state;
struct drm_crtc_state *new_crtc_state;
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
new_conn_state = drm_atomic_get_new_connector_state(state, connector);
if (WARN_ON(!new_conn_state))
return -EINVAL;
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
if (WARN_ON(!new_crtc_state))
return -EINVAL;
display = &connector->display_info;
mode = &new_crtc_state->adjusted_mode;
hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB;
@ -363,7 +360,7 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
if (display->is_hdmi) {
hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK,
HDMI_VIDEO_MODE_HDMI);
rk3066_hdmi_config_avi(hdmi, mode);
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
} else {
hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK, 0);
}
@ -386,15 +383,15 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi,
return 0;
}
static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder,
struct drm_atomic_state *state)
static void rk3066_hdmi_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
struct drm_connector_state *conn_state;
struct drm_crtc_state *crtc_state;
int mux, val;
conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector);
conn_state = drm_atomic_get_new_connector_state(state, hdmi->connector);
if (WARN_ON(!conn_state))
return;
@ -402,7 +399,7 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder,
if (WARN_ON(!crtc_state))
return;
mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, &hdmi->encoder.encoder);
if (mux)
val = (HDMI_VIDEO_SEL << 16) | HDMI_VIDEO_SEL;
else
@ -413,13 +410,13 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder,
DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder enable select: vop%s\n",
(mux) ? "1" : "0");
rk3066_hdmi_setup(hdmi, &crtc_state->adjusted_mode);
rk3066_hdmi_setup(hdmi, state);
}
static void rk3066_hdmi_encoder_disable(struct drm_encoder *encoder,
struct drm_atomic_state *state)
static void rk3066_hdmi_bridge_atomic_disable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder disable\n");
@ -450,39 +447,34 @@ rk3066_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
static const
struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = {
.atomic_check = rk3066_hdmi_encoder_atomic_check,
.atomic_enable = rk3066_hdmi_encoder_enable,
.atomic_disable = rk3066_hdmi_encoder_disable,
};
static enum drm_connector_status
rk3066_hdmi_connector_detect(struct drm_connector *connector, bool force)
rk3066_hdmi_bridge_detect(struct drm_bridge *bridge)
{
struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
return (hdmi_readb(hdmi, HDMI_HPG_MENS_STA) & HDMI_HPG_IN_STATUS_HIGH) ?
connector_status_connected : connector_status_disconnected;
}
static int rk3066_hdmi_connector_get_modes(struct drm_connector *connector)
static const struct drm_edid *
rk3066_hdmi_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector)
{
struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge);
const struct drm_edid *drm_edid;
int ret = 0;
if (!hdmi->ddc)
return 0;
drm_edid = drm_edid_read_ddc(connector, bridge->ddc);
if (!drm_edid)
dev_dbg(hdmi->dev, "failed to get edid\n");
drm_edid = drm_edid_read_ddc(connector, hdmi->ddc);
drm_edid_connector_update(connector, drm_edid);
ret = drm_edid_connector_add_modes(connector);
drm_edid_free(drm_edid);
return ret;
return drm_edid;
}
static enum drm_mode_status
rk3066_hdmi_connector_mode_valid(struct drm_connector *connector,
const struct drm_display_mode *mode)
rk3066_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
u32 vic = drm_match_cea_mode(mode);
@ -492,82 +484,19 @@ rk3066_hdmi_connector_mode_valid(struct drm_connector *connector,
return MODE_BAD;
}
static struct drm_encoder *
rk3066_hdmi_connector_best_encoder(struct drm_connector *connector)
{
struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
return &hdmi->encoder.encoder;
}
static int
rk3066_hdmi_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
if (maxX > 1920)
maxX = 1920;
if (maxY > 1080)
maxY = 1080;
return drm_helper_probe_single_connector_modes(connector, maxX, maxY);
}
static void rk3066_hdmi_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
static const struct drm_connector_funcs rk3066_hdmi_connector_funcs = {
.fill_modes = rk3066_hdmi_probe_single_connector_modes,
.detect = rk3066_hdmi_connector_detect,
.destroy = rk3066_hdmi_connector_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
static const struct drm_bridge_funcs rk3066_hdmi_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_enable = rk3066_hdmi_bridge_atomic_enable,
.atomic_disable = rk3066_hdmi_bridge_atomic_disable,
.detect = rk3066_hdmi_bridge_detect,
.edid_read = rk3066_hdmi_bridge_edid_read,
.hdmi_clear_infoframe = rk3066_hdmi_bridge_clear_infoframe,
.hdmi_write_infoframe = rk3066_hdmi_bridge_write_infoframe,
.mode_valid = rk3066_hdmi_bridge_mode_valid,
};
static const
struct drm_connector_helper_funcs rk3066_hdmi_connector_helper_funcs = {
.get_modes = rk3066_hdmi_connector_get_modes,
.mode_valid = rk3066_hdmi_connector_mode_valid,
.best_encoder = rk3066_hdmi_connector_best_encoder,
};
static int
rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
{
struct drm_encoder *encoder = &hdmi->encoder.encoder;
struct device *dev = hdmi->dev;
encoder->possible_crtcs =
drm_of_find_possible_crtcs(drm, dev->of_node);
/*
* If we failed to find the CRTC(s) which this encoder is
* supposed to be connected to, it's because the CRTC has
* not been registered yet. Defer probing, and hope that
* the required CRTC is added later.
*/
if (encoder->possible_crtcs == 0)
return -EPROBE_DEFER;
drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs);
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
&rk3066_hdmi_connector_helper_funcs);
drm_connector_init_with_ddc(drm, &hdmi->connector,
&rk3066_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
hdmi->ddc);
drm_connector_attach_encoder(&hdmi->connector, encoder);
return 0;
}
static irqreturn_t rk3066_hdmi_hardirq(int irq, void *dev_id)
{
@ -597,7 +526,7 @@ static irqreturn_t rk3066_hdmi_irq(int irq, void *dev_id)
{
struct rk3066_hdmi *hdmi = dev_id;
drm_helper_hpd_irq_event(hdmi->connector.dev);
drm_helper_hpd_irq_event(hdmi->connector->dev);
return IRQ_HANDLED;
}
@ -720,7 +649,7 @@ static struct i2c_adapter *rk3066_hdmi_i2c_adapter(struct rk3066_hdmi *hdmi)
strscpy(adap->name, "RK3066 HDMI", sizeof(adap->name));
i2c_set_adapdata(adap, hdmi);
ret = i2c_add_adapter(adap);
ret = devm_i2c_add_adapter(hdmi->dev, adap);
if (ret) {
DRM_DEV_ERROR(hdmi->dev, "cannot add %s I2C adapter\n",
adap->name);
@ -735,6 +664,66 @@ static struct i2c_adapter *rk3066_hdmi_i2c_adapter(struct rk3066_hdmi *hdmi)
return adap;
}
static int
rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
{
struct drm_encoder *encoder = &hdmi->encoder.encoder;
struct device *dev = hdmi->dev;
int ret;
encoder->possible_crtcs =
drm_of_find_possible_crtcs(drm, dev->of_node);
/*
* If we failed to find the CRTC(s) which this encoder is
* supposed to be connected to, it's because the CRTC has
* not been registered yet. Defer probing, and hope that
* the required CRTC is added later.
*/
if (encoder->possible_crtcs == 0)
return -EPROBE_DEFER;
drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs);
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
hdmi->bridge.driver_private = hdmi;
hdmi->bridge.funcs = &rk3066_hdmi_bridge_funcs;
hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT |
DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_HDMI |
DRM_BRIDGE_OP_HPD;
hdmi->bridge.of_node = hdmi->dev->of_node;
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Rockchip";
hdmi->bridge.product = "RK3066 HDMI";
hdmi->bridge.ddc = rk3066_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->bridge.ddc))
return PTR_ERR(hdmi->bridge.ddc);
if (IS_ERR(hdmi->bridge.ddc))
return PTR_ERR(hdmi->bridge.ddc);
ret = devm_drm_bridge_add(dev, &hdmi->bridge);
if (ret)
return ret;
ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
hdmi->connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(hdmi->connector)) {
ret = PTR_ERR(hdmi->connector);
dev_err(hdmi->dev, "failed to init bridge connector: %d\n", ret);
return ret;
}
drm_connector_attach_encoder(hdmi->connector, encoder);
return 0;
}
static int rk3066_hdmi_bind(struct device *dev, struct device *master,
void *data)
{
@ -781,13 +770,6 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
/* internal hclk = hdmi_hclk / 25 */
hdmi_writeb(hdmi, HDMI_INTERNAL_CLK_DIVIDER, 25);
hdmi->ddc = rk3066_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->ddc)) {
ret = PTR_ERR(hdmi->ddc);
hdmi->ddc = NULL;
goto err_disable_hclk;
}
rk3066_hdmi_set_power_mode(hdmi, HDMI_SYS_POWER_MODE_B);
usleep_range(999, 1000);
hdmi_writeb(hdmi, HDMI_INTR_MASK1, HDMI_INTR_HOTPLUG);
@ -798,7 +780,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
ret = rk3066_hdmi_register(drm, hdmi);
if (ret)
goto err_disable_i2c;
goto err_disable_hclk;
dev_set_drvdata(dev, hdmi);
@ -813,10 +795,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
return 0;
err_cleanup_hdmi:
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
err_disable_i2c:
i2c_put_adapter(hdmi->ddc);
err_disable_hclk:
clk_disable_unprepare(hdmi->hclk);
@ -828,10 +807,8 @@ static void rk3066_hdmi_unbind(struct device *dev, struct device *master,
{
struct rk3066_hdmi *hdmi = dev_get_drvdata(dev);
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
i2c_put_adapter(hdmi->ddc);
clk_disable_unprepare(hdmi->hclk);
}

View File

@ -1321,10 +1321,16 @@ static struct drm_plane *tegra_dc_add_shared_planes(struct drm_device *drm,
if (wgrp->dc == dc->pipe) {
for (j = 0; j < wgrp->num_windows; j++) {
unsigned int index = wgrp->windows[j];
enum drm_plane_type type;
if (primary)
type = DRM_PLANE_TYPE_OVERLAY;
else
type = DRM_PLANE_TYPE_PRIMARY;
plane = tegra_shared_plane_create(drm, dc,
wgrp->index,
index);
index, type);
if (IS_ERR(plane))
return plane;
@ -1332,10 +1338,8 @@ static struct drm_plane *tegra_dc_add_shared_planes(struct drm_device *drm,
* Choose the first shared plane owned by this
* head as the primary plane.
*/
if (!primary) {
plane->type = DRM_PLANE_TYPE_PRIMARY;
if (!primary)
primary = plane;
}
}
}
}
@ -1389,7 +1393,10 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
if (crtc->state)
tegra_crtc_atomic_destroy_state(crtc, crtc->state);
__drm_atomic_helper_crtc_reset(crtc, &state->base);
if (state)
__drm_atomic_helper_crtc_reset(crtc, &state->base);
else
__drm_atomic_helper_crtc_reset(crtc, NULL);
}
static struct drm_crtc_state *

View File

@ -501,14 +501,9 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
dpaux->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
if (IS_ERR(dpaux->vdd)) {
if (PTR_ERR(dpaux->vdd) != -ENODEV) {
if (PTR_ERR(dpaux->vdd) != -EPROBE_DEFER)
dev_err(&pdev->dev,
"failed to get VDD supply: %ld\n",
PTR_ERR(dpaux->vdd));
return PTR_ERR(dpaux->vdd);
}
if (PTR_ERR(dpaux->vdd) != -ENODEV)
return dev_err_probe(&pdev->dev, PTR_ERR(dpaux->vdd),
"failed to get VDD supply\n");
dpaux->vdd = NULL;
}

View File

@ -30,6 +30,14 @@ int falcon_wait_idle(struct falcon *falcon)
(value == 0), 10, 100000);
}
static int falcon_dma_wait_not_full(struct falcon *falcon)
{
u32 value;
return readl_poll_timeout(falcon->regs + FALCON_DMATRFCMD, value,
!(value & FALCON_DMATRFCMD_FULL), 10, 100000);
}
static int falcon_dma_wait_idle(struct falcon *falcon)
{
u32 value;
@ -44,6 +52,7 @@ static int falcon_copy_chunk(struct falcon *falcon,
enum falcon_memory target)
{
u32 cmd = FALCON_DMATRFCMD_SIZE_256B;
int err;
if (target == FALCON_MEMORY_IMEM)
cmd |= FALCON_DMATRFCMD_IMEM;
@ -56,11 +65,15 @@ static int falcon_copy_chunk(struct falcon *falcon,
*/
cmd |= FALCON_DMATRFCMD_DMACTX(1);
err = falcon_dma_wait_not_full(falcon);
if (err < 0)
return err;
falcon_writel(falcon, offset, FALCON_DMATRFMOFFS);
falcon_writel(falcon, base, FALCON_DMATRFFBOFFS);
falcon_writel(falcon, cmd, FALCON_DMATRFCMD);
return falcon_dma_wait_idle(falcon);
return 0;
}
static void falcon_copy_firmware_image(struct falcon *falcon,
@ -191,6 +204,11 @@ int falcon_boot(struct falcon *falcon)
falcon_copy_chunk(falcon, falcon->firmware.code.offset + offset,
offset, FALCON_MEMORY_IMEM);
/* wait for DMA to complete */
err = falcon_dma_wait_idle(falcon);
if (err < 0)
return err;
/* setup falcon interrupts */
falcon_writel(falcon, FALCON_IRQMSET_EXT(0xff) |
FALCON_IRQMSET_SWGEN1 |

View File

@ -47,6 +47,7 @@
#define FALCON_DMATRFMOFFS 0x00001114
#define FALCON_DMATRFCMD 0x00001118
#define FALCON_DMATRFCMD_FULL (1 << 0)
#define FALCON_DMATRFCMD_IDLE (1 << 1)
#define FALCON_DMATRFCMD_IMEM (1 << 4)
#define FALCON_DMATRFCMD_SIZE_256B (6 << 8)

View File

@ -17,7 +17,6 @@
#include <drm/drm_drv.h>
#include <drm/drm_prime.h>
#include <drm/tegra_drm.h>
#include "drm.h"
#include "gem.h"

View File

@ -755,9 +755,9 @@ static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = {
struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
struct tegra_dc *dc,
unsigned int wgrp,
unsigned int index)
unsigned int index,
enum drm_plane_type type)
{
enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
struct tegra_drm *tegra = drm->dev_private;
struct tegra_display_hub *hub = tegra->hub;
struct tegra_shared_plane *plane;

View File

@ -80,7 +80,8 @@ void tegra_display_hub_cleanup(struct tegra_display_hub *hub);
struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
struct tegra_dc *dc,
unsigned int wgrp,
unsigned int index);
unsigned int index,
enum drm_plane_type type);
int tegra_display_hub_atomic_check(struct drm_device *drm,
struct drm_atomic_state *state);

View File

@ -200,6 +200,11 @@ static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
.atomic_check = tegra_rgb_encoder_atomic_check,
};
static void tegra_dc_of_node_put(void *data)
{
of_node_put(data);
}
int tegra_dc_rgb_probe(struct tegra_dc *dc)
{
struct device_node *np;
@ -207,7 +212,14 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc)
int err;
np = of_get_child_by_name(dc->dev->of_node, "rgb");
if (!np || !of_device_is_available(np))
if (!np)
return -ENODEV;
err = devm_add_action_or_reset(dc->dev, tegra_dc_of_node_put, np);
if (err < 0)
return err;
if (!of_device_is_available(np))
return -ENODEV;
rgb = devm_kzalloc(dc->dev, sizeof(*rgb), GFP_KERNEL);

View File

@ -3,6 +3,7 @@
config DRM_APPLETBDRM
tristate "DRM support for Apple Touch Bars"
depends on DRM && USB && MMU
depends on X86 || COMPILE_TEST
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
help

View File

@ -908,16 +908,14 @@ static int st7571_probe(struct i2c_client *client)
st7571->hwbuf = devm_kzalloc(&client->dev,
(st7571->nlines * st7571->ncols * st7571->bpp) / 8,
GFP_KERNEL);
if (IS_ERR(st7571->hwbuf))
return dev_err_probe(&client->dev, PTR_ERR(st7571->hwbuf),
"Failed to allocate intermediate buffer\n");
if (!st7571->hwbuf)
return -ENOMEM;
st7571->row = devm_kzalloc(&client->dev,
(st7571->ncols * st7571->bpp),
GFP_KERNEL);
if (IS_ERR(st7571->row))
return dev_err_probe(&client->dev, PTR_ERR(st7571->row),
"Failed to allocate row buffer\n");
if (!st7571->row)
return -ENOMEM;
ret = st7571_mode_config_init(st7571);
if (ret)

View File

@ -194,7 +194,7 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc,
i++;
}
vkms_state->active_planes = kcalloc(i, sizeof(plane), GFP_KERNEL);
vkms_state->active_planes = kcalloc(i, sizeof(*vkms_state->active_planes), GFP_KERNEL);
if (!vkms_state->active_planes)
return -ENOMEM;
vkms_state->num_active_planes = i;

View File

@ -41,7 +41,6 @@ static int host1x_subdev_add(struct host1x_device *device,
struct device_node *np)
{
struct host1x_subdev *subdev;
struct device_node *child;
int err;
subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
@ -56,13 +55,12 @@ static int host1x_subdev_add(struct host1x_device *device,
mutex_unlock(&device->subdevs_lock);
/* recursively add children */
for_each_child_of_node(np, child) {
for_each_child_of_node_scoped(np, child) {
if (of_match_node(driver->subdevs, child) &&
of_device_is_available(child)) {
err = host1x_subdev_add(device, driver, child);
if (err < 0) {
/* XXX cleanup? */
of_node_put(child);
return err;
}
}
@ -90,17 +88,14 @@ static void host1x_subdev_del(struct host1x_subdev *subdev)
static int host1x_device_parse_dt(struct host1x_device *device,
struct host1x_driver *driver)
{
struct device_node *np;
int err;
for_each_child_of_node(device->dev.parent->of_node, np) {
for_each_child_of_node_scoped(device->dev.parent->of_node, np) {
if (of_match_node(driver->subdevs, np) &&
of_device_is_available(np)) {
err = host1x_subdev_add(device, driver, np);
if (err < 0) {
of_node_put(np);
if (err < 0)
return err;
}
}
}

View File

@ -247,8 +247,6 @@ static int host1x_cdma_wait_pushbuffer_space(struct host1x *host1x,
trace_host1x_wait_cdma(dev_name(cdma_to_channel(cdma)->dev),
CDMA_EVENT_PUSH_BUFFER_SPACE);
host1x_hw_cdma_flush(host1x, cdma);
/* If somebody has managed to already start waiting, yield */
if (cdma->event != CDMA_EVENT_NONE) {
mutex_unlock(&cdma->lock);
@ -591,7 +589,6 @@ int host1x_cdma_begin(struct host1x_cdma *cdma, struct host1x_job *job)
*/
void host1x_cdma_push(struct host1x_cdma *cdma, u32 op1, u32 op2)
{
struct host1x *host1x = cdma_to_host1x(cdma);
struct push_buffer *pb = &cdma->push_buffer;
u32 slots_free = cdma->slots_free;
@ -599,11 +596,9 @@ void host1x_cdma_push(struct host1x_cdma *cdma, u32 op1, u32 op2)
trace_host1x_cdma_push(dev_name(cdma_to_channel(cdma)->dev),
op1, op2);
if (slots_free == 0) {
host1x_hw_cdma_flush(host1x, cdma);
if (slots_free == 0)
slots_free = host1x_cdma_wait_locked(cdma,
CDMA_EVENT_PUSH_BUFFER_SPACE);
}
cdma->slots_free = slots_free - 1;
cdma->slots_used++;

View File

@ -726,7 +726,7 @@ static void fourcc_pointer(struct kunit *kunittest)
static const struct fourcc_struct try_ch[] = {
{ 0x41424344, "ABCD (0x41424344)", },
};
static const struct fourcc_struct try_cn[] = {
static const struct fourcc_struct try_chR[] = {
{ 0x41424344, "DCBA (0x44434241)", },
};
static const struct fourcc_struct try_cl[] = {
@ -738,7 +738,7 @@ static void fourcc_pointer(struct kunit *kunittest)
fourcc_pointer_test(kunittest, try_cc, ARRAY_SIZE(try_cc), "%p4cc");
fourcc_pointer_test(kunittest, try_ch, ARRAY_SIZE(try_ch), "%p4ch");
fourcc_pointer_test(kunittest, try_cn, ARRAY_SIZE(try_cn), "%p4cn");
fourcc_pointer_test(kunittest, try_chR, ARRAY_SIZE(try_chR), "%p4chR");
fourcc_pointer_test(kunittest, try_cl, ARRAY_SIZE(try_cl), "%p4cl");
fourcc_pointer_test(kunittest, try_cb, ARRAY_SIZE(try_cb), "%p4cb");
}

View File

@ -1805,9 +1805,8 @@ char *fourcc_string(char *buf, char *end, const u32 *fourcc,
orig = get_unaligned(fourcc);
switch (fmt[2]) {
case 'h':
break;
case 'n':
orig = swab32(orig);
if (fmt[3] == 'R')
orig = swab32(orig);
break;
case 'l':
orig = (__force u32)cpu_to_le32(orig);
@ -2397,6 +2396,12 @@ early_param("no_hash_pointers", no_hash_pointers_enable);
* read the documentation (path below) first.
* - 'NF' For a netdev_features_t
* - '4cc' V4L2 or DRM FourCC code, with endianness and raw numerical value.
* - '4c[h[R]lb]' For generic FourCC code with raw numerical value. Both are
* displayed in the big-endian format. This is the opposite of V4L2 or
* DRM FourCCs.
* The additional specifiers define what endianness is used to load
* the stored bytes. The data might be interpreted using the host,
* reversed host byte order, little-endian, or big-endian.
* - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
* a certain separator (' ' by default):
* C colon

View File

@ -6891,7 +6891,7 @@ sub process {
($extension eq "f" &&
defined $qualifier && $qualifier !~ /^w/) ||
($extension eq "4" &&
defined $qualifier && $qualifier !~ /^c[hnlbc]/)) {
defined $qualifier && $qualifier !~ /^c(?:[hlbc]|hR)$/)) {
$bad_specifier = $specifier;
last;
}