mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
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:
commit
f9fa012293
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -23,6 +23,7 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
backlight: true
|
||||
port: true
|
||||
reset-gpios: true
|
||||
iovcc-supply:
|
||||
description: regulator that supplies the iovcc voltage
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
backlight: true
|
||||
port: true
|
||||
reset-gpios: true
|
||||
iovcc-supply:
|
||||
description: regulator that supplies the iovcc voltage
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
247
drivers/gpu/drm/panel/panel-boe-td4320.c
Normal file
247
drivers/gpu/drm/panel/panel-boe-td4320.c
Normal 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");
|
||||
|
|
@ -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"),
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user