diff options
author | 2023-02-21 18:24:12 -0800 | |
---|---|---|
committer | 2023-02-21 18:24:12 -0800 | |
commit | 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 (patch) | |
tree | cc5c2d0a898769fd59549594fedb3ee6f84e59a0 /drivers/gpu/drm/bridge/tc358764.c | |
download | linux-5b7c4cabbb65f5c469464da6c5f614cbd7f730f2.tar.gz linux-5b7c4cabbb65f5c469464da6c5f614cbd7f730f2.zip |
Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-nextgrafted
Pull networking updates from Jakub Kicinski:
"Core:
- Add dedicated kmem_cache for typical/small skb->head, avoid having
to access struct page at kfree time, and improve memory use.
- Introduce sysctl to set default RPS configuration for new netdevs.
- Define Netlink protocol specification format which can be used to
describe messages used by each family and auto-generate parsers.
Add tools for generating kernel data structures and uAPI headers.
- Expose all net/core sysctls inside netns.
- Remove 4s sleep in netpoll if carrier is instantly detected on
boot.
- Add configurable limit of MDB entries per port, and port-vlan.
- Continue populating drop reasons throughout the stack.
- Retire a handful of legacy Qdiscs and classifiers.
Protocols:
- Support IPv4 big TCP (TSO frames larger than 64kB).
- Add IP_LOCAL_PORT_RANGE socket option, to control local port range
on socket by socket basis.
- Track and report in procfs number of MPTCP sockets used.
- Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path
manager.
- IPv6: don't check net.ipv6.route.max_size and rely on garbage
collection to free memory (similarly to IPv4).
- Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986).
- ICMP: add per-rate limit counters.
- Add support for user scanning requests in ieee802154.
- Remove static WEP support.
- Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate
reporting.
- WiFi 7 EHT channel puncturing support (client & AP).
BPF:
- Add a rbtree data structure following the "next-gen data structure"
precedent set by recently added linked list, that is, by using
kfunc + kptr instead of adding a new BPF map type.
- Expose XDP hints via kfuncs with initial support for RX hash and
timestamp metadata.
- Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to
better support decap on GRE tunnel devices not operating in collect
metadata.
- Improve x86 JIT's codegen for PROBE_MEM runtime error checks.
- Remove the need for trace_printk_lock for bpf_trace_printk and
bpf_trace_vprintk helpers.
- Extend libbpf's bpf_tracing.h support for tracing arguments of
kprobes/uprobes and syscall as a special case.
- Significantly reduce the search time for module symbols by
livepatch and BPF.
- Enable cpumasks to be used as kptrs, which is useful for tracing
programs tracking which tasks end up running on which CPUs in
different time intervals.
- Add support for BPF trampoline on s390x and riscv64.
- Add capability to export the XDP features supported by the NIC.
- Add __bpf_kfunc tag for marking kernel functions as kfuncs.
- Add cgroup.memory=nobpf kernel parameter option to disable BPF
memory accounting for container environments.
Netfilter:
- Remove the CLUSTERIP target. It has been marked as obsolete for
years, and we still have WARN splats wrt races of the out-of-band
/proc interface installed by this target.
- Add 'destroy' commands to nf_tables. They are identical to the
existing 'delete' commands, but do not return an error if the
referenced object (set, chain, rule...) did not exist.
Driver API:
- Improve cpumask_local_spread() locality to help NICs set the right
IRQ affinity on AMD platforms.
- Separate C22 and C45 MDIO bus transactions more clearly.
- Introduce new DCB table to control DSCP rewrite on egress.
- Support configuration of Physical Layer Collision Avoidance (PLCA)
Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of
shared medium Ethernet.
- Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing
preemption of low priority frames by high priority frames.
- Add support for controlling MACSec offload using netlink SET.
- Rework devlink instance refcounts to allow registration and
de-registration under the instance lock. Split the code into
multiple files, drop some of the unnecessarily granular locks and
factor out common parts of netlink operation handling.
- Add TX frame aggregation parameters (for USB drivers).
- Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning
messages with notifications for debug.
- Allow offloading of UDP NEW connections via act_ct.
- Add support for per action HW stats in TC.
- Support hardware miss to TC action (continue processing in SW from
a specific point in the action chain).
- Warn if old Wireless Extension user space interface is used with
modern cfg80211/mac80211 drivers. Do not support Wireless
Extensions for Wi-Fi 7 devices at all. Everyone should switch to
using nl80211 interface instead.
- Improve the CAN bit timing configuration. Use extack to return
error messages directly to user space, update the SJW handling,
including the definition of a new default value that will benefit
CAN-FD controllers, by increasing their oscillator tolerance.
New hardware / drivers:
- Ethernet:
- nVidia BlueField-3 support (control traffic driver)
- Ethernet support for imx93 SoCs
- Motorcomm yt8531 gigabit Ethernet PHY
- onsemi NCN26000 10BASE-T1S PHY (with support for PLCA)
- Microchip LAN8841 PHY (incl. cable diagnostics and PTP)
- Amlogic gxl MDIO mux
- WiFi:
- RealTek RTL8188EU (rtl8xxxu)
- Qualcomm Wi-Fi 7 devices (ath12k)
- CAN:
- Renesas R-Car V4H
Drivers:
- Bluetooth:
- Set Per Platform Antenna Gain (PPAG) for Intel controllers.
- Ethernet NICs:
- Intel (1G, igc):
- support TSN / Qbv / packet scheduling features of i226 model
- Intel (100G, ice):
- use GNSS subsystem instead of TTY
- multi-buffer XDP support
- extend support for GPIO pins to E823 devices
- nVidia/Mellanox:
- update the shared buffer configuration on PFC commands
- implement PTP adjphase function for HW offset control
- TC support for Geneve and GRE with VF tunnel offload
- more efficient crypto key management method
- multi-port eswitch support
- Netronome/Corigine:
- add DCB IEEE support
- support IPsec offloading for NFP3800
- Freescale/NXP (enetc):
- support XDP_REDIRECT for XDP non-linear buffers
- improve reconfig, avoid link flap and waiting for idle
- support MAC Merge layer
- Other NICs:
- sfc/ef100: add basic devlink support for ef100
- ionic: rx_push mode operation (writing descriptors via MMIO)
- bnxt: use the auxiliary bus abstraction for RDMA
- r8169: disable ASPM and reset bus in case of tx timeout
- cpsw: support QSGMII mode for J721e CPSW9G
- cpts: support pulse-per-second output
- ngbe: add an mdio bus driver
- usbnet: optimize usbnet_bh() by avoiding unnecessary queuing
- r8152: handle devices with FW with NCM support
- amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation
- virtio-net: support multi buffer XDP
- virtio/vsock: replace virtio_vsock_pkt with sk_buff
- tsnep: XDP support
- Ethernet high-speed switches:
- nVidia/Mellanox (mlxsw):
- add support for latency TLV (in FW control messages)
- Microchip (sparx5):
- separate explicit and implicit traffic forwarding rules, make
the implicit rules always active
- add support for egress DSCP rewrite
- IS0 VCAP support (Ingress Classification)
- IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS
etc.)
- ES2 VCAP support (Egress Access Control)
- support for Per-Stream Filtering and Policing (802.1Q,
8.6.5.1)
- Ethernet embedded switches:
- Marvell (mv88e6xxx):
- add MAB (port auth) offload support
- enable PTP receive for mv88e6390
- NXP (ocelot):
- support MAC Merge layer
- support for the the vsc7512 internal copper phys
- Microchip:
- lan9303: convert to PHYLINK
- lan966x: support TC flower filter statistics
- lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x
- lan937x: support Credit Based Shaper configuration
- ksz9477: support Energy Efficient Ethernet
- other:
- qca8k: convert to regmap read/write API, use bulk operations
- rswitch: Improve TX timestamp accuracy
- Intel WiFi (iwlwifi):
- EHT (Wi-Fi 7) rate reporting
- STEP equalizer support: transfer some STEP (connection to radio
on platforms with integrated wifi) related parameters from the
BIOS to the firmware.
- Qualcomm 802.11ax WiFi (ath11k):
- IPQ5018 support
- Fine Timing Measurement (FTM) responder role support
- channel 177 support
- MediaTek WiFi (mt76):
- per-PHY LED support
- mt7996: EHT (Wi-Fi 7) support
- Wireless Ethernet Dispatch (WED) reset support
- switch to using page pool allocator
- RealTek WiFi (rtw89):
- support new version of Bluetooth co-existance
- Mobile:
- rmnet: support TX aggregation"
* tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits)
page_pool: add a comment explaining the fragment counter usage
net: ethtool: fix __ethtool_dev_mm_supported() implementation
ethtool: pse-pd: Fix double word in comments
xsk: add linux/vmalloc.h to xsk.c
sefltests: netdevsim: wait for devlink instance after netns removal
selftest: fib_tests: Always cleanup before exit
net/mlx5e: Align IPsec ASO result memory to be as required by hardware
net/mlx5e: TC, Set CT miss to the specific ct action instance
net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG
net/mlx5: Refactor tc miss handling to a single function
net/mlx5: Kconfig: Make tc offload depend on tc skb extension
net/sched: flower: Support hardware miss to tc action
net/sched: flower: Move filter handle initialization earlier
net/sched: cls_api: Support hardware miss to tc action
net/sched: Rename user cookie and act cookie
sfc: fix builds without CONFIG_RTC_LIB
sfc: clean up some inconsistent indentings
net/mlx4_en: Introduce flexible array to silence overflow warning
net: lan966x: Fix possible deadlock inside PTP
net/ulp: Remove redundant ->clone() test in inet_clone_ulp().
...
Diffstat (limited to 'drivers/gpu/drm/bridge/tc358764.c')
-rw-r--r-- | drivers/gpu/drm/bridge/tc358764.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c new file mode 100644 index 000000000..53259c12d --- /dev/null +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -0,0 +1,412 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Samsung Electronics Co., Ltd + * + * Authors: + * Andrzej Hajda <a.hajda@samsung.com> + * Maciej Purski <m.purski@samsung.com> + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of_graph.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_of.h> +#include <drm/drm_print.h> + +#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) +#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) + +/* PPI layer registers */ +#define PPI_STARTPPI 0x0104 /* START control bit */ +#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */ +#define PPI_LANEENABLE 0x0134 /* Enables each lane */ +#define PPI_TX_RX_TA 0x013C /* BTA timing parameters */ +#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* Assertion timer for Lane 0 */ +#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* Assertion timer for Lane 1 */ +#define PPI_D2S_CLRSIPOCOUNT 0x016C /* Assertion timer for Lane 2 */ +#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* Assertion timer for Lane 3 */ +#define PPI_START_FUNCTION 1 + +/* DSI layer registers */ +#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */ +#define DSI_LANEENABLE 0x0210 /* Enables each lane */ +#define DSI_RX_START 1 + +/* Video path registers */ +#define VP_CTRL 0x0450 /* Video Path Control */ +#define VP_CTRL_MSF(v) FLD_VAL(v, 0, 0) /* Magic square in RGB666 */ +#define VP_CTRL_VTGEN(v) FLD_VAL(v, 4, 4) /* Use chip clock for timing */ +#define VP_CTRL_EVTMODE(v) FLD_VAL(v, 5, 5) /* Event mode */ +#define VP_CTRL_RGB888(v) FLD_VAL(v, 8, 8) /* RGB888 mode */ +#define VP_CTRL_VSDELAY(v) FLD_VAL(v, 31, 20) /* VSYNC delay */ +#define VP_CTRL_HSPOL BIT(17) /* Polarity of HSYNC signal */ +#define VP_CTRL_DEPOL BIT(18) /* Polarity of DE signal */ +#define VP_CTRL_VSPOL BIT(19) /* Polarity of VSYNC signal */ +#define VP_HTIM1 0x0454 /* Horizontal Timing Control 1 */ +#define VP_HTIM1_HBP(v) FLD_VAL(v, 24, 16) +#define VP_HTIM1_HSYNC(v) FLD_VAL(v, 8, 0) +#define VP_HTIM2 0x0458 /* Horizontal Timing Control 2 */ +#define VP_HTIM2_HFP(v) FLD_VAL(v, 24, 16) +#define VP_HTIM2_HACT(v) FLD_VAL(v, 10, 0) +#define VP_VTIM1 0x045C /* Vertical Timing Control 1 */ +#define VP_VTIM1_VBP(v) FLD_VAL(v, 23, 16) +#define VP_VTIM1_VSYNC(v) FLD_VAL(v, 7, 0) +#define VP_VTIM2 0x0460 /* Vertical Timing Control 2 */ +#define VP_VTIM2_VFP(v) FLD_VAL(v, 23, 16) +#define VP_VTIM2_VACT(v) FLD_VAL(v, 10, 0) +#define VP_VFUEN 0x0464 /* Video Frame Timing Update Enable */ + +/* LVDS registers */ +#define LV_MX0003 0x0480 /* Mux input bit 0 to 3 */ +#define LV_MX0407 0x0484 /* Mux input bit 4 to 7 */ +#define LV_MX0811 0x0488 /* Mux input bit 8 to 11 */ +#define LV_MX1215 0x048C /* Mux input bit 12 to 15 */ +#define LV_MX1619 0x0490 /* Mux input bit 16 to 19 */ +#define LV_MX2023 0x0494 /* Mux input bit 20 to 23 */ +#define LV_MX2427 0x0498 /* Mux input bit 24 to 27 */ +#define LV_MX(b0, b1, b2, b3) (FLD_VAL(b0, 4, 0) | FLD_VAL(b1, 12, 8) | \ + FLD_VAL(b2, 20, 16) | FLD_VAL(b3, 28, 24)) + +/* Input bit numbers used in mux registers */ +enum { + LVI_R0, + LVI_R1, + LVI_R2, + LVI_R3, + LVI_R4, + LVI_R5, + LVI_R6, + LVI_R7, + LVI_G0, + LVI_G1, + LVI_G2, + LVI_G3, + LVI_G4, + LVI_G5, + LVI_G6, + LVI_G7, + LVI_B0, + LVI_B1, + LVI_B2, + LVI_B3, + LVI_B4, + LVI_B5, + LVI_B6, + LVI_B7, + LVI_HS, + LVI_VS, + LVI_DE, + LVI_L0 +}; + +#define LV_CFG 0x049C /* LVDS Configuration */ +#define LV_PHY0 0x04A0 /* LVDS PHY 0 */ +#define LV_PHY0_RST(v) FLD_VAL(v, 22, 22) /* PHY reset */ +#define LV_PHY0_IS(v) FLD_VAL(v, 15, 14) +#define LV_PHY0_ND(v) FLD_VAL(v, 4, 0) /* Frequency range select */ +#define LV_PHY0_PRBS_ON(v) FLD_VAL(v, 20, 16) /* Clock/Data Flag pins */ + +/* System registers */ +#define SYS_RST 0x0504 /* System Reset */ +#define SYS_ID 0x0580 /* System ID */ + +#define SYS_RST_I2CS BIT(0) /* Reset I2C-Slave controller */ +#define SYS_RST_I2CM BIT(1) /* Reset I2C-Master controller */ +#define SYS_RST_LCD BIT(2) /* Reset LCD controller */ +#define SYS_RST_BM BIT(3) /* Reset Bus Management controller */ +#define SYS_RST_DSIRX BIT(4) /* Reset DSI-RX and App controller */ +#define SYS_RST_REG BIT(5) /* Reset Register module */ + +#define LPX_PERIOD 2 +#define TTA_SURE 3 +#define TTA_GET 0x20000 + +/* Lane enable PPI and DSI register bits */ +#define LANEENABLE_CLEN BIT(0) +#define LANEENABLE_L0EN BIT(1) +#define LANEENABLE_L1EN BIT(2) +#define LANEENABLE_L2EN BIT(3) +#define LANEENABLE_L3EN BIT(4) + +/* LVCFG fields */ +#define LV_CFG_LVEN BIT(0) +#define LV_CFG_LVDLINK BIT(1) +#define LV_CFG_CLKPOL1 BIT(2) +#define LV_CFG_CLKPOL2 BIT(3) + +static const char * const tc358764_supplies[] = { + "vddc", "vddio", "vddlvds" +}; + +struct tc358764 { + struct device *dev; + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)]; + struct gpio_desc *gpio_reset; + int error; +}; + +static int tc358764_clear_error(struct tc358764 *ctx) +{ + int ret = ctx->error; + + ctx->error = 0; + return ret; +} + +static void tc358764_read(struct tc358764 *ctx, u16 addr, u32 *val) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + ssize_t ret; + + if (ctx->error) + return; + + cpu_to_le16s(&addr); + ret = mipi_dsi_generic_read(dsi, &addr, sizeof(addr), val, sizeof(*val)); + if (ret >= 0) + le32_to_cpus(val); + + dev_dbg(ctx->dev, "read: %d, addr: %d\n", addr, *val); +} + +static void tc358764_write(struct tc358764 *ctx, u16 addr, u32 val) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + ssize_t ret; + u8 data[6]; + + if (ctx->error) + return; + + data[0] = addr; + data[1] = addr >> 8; + data[2] = val; + data[3] = val >> 8; + data[4] = val >> 16; + data[5] = val >> 24; + + ret = mipi_dsi_generic_write(dsi, data, sizeof(data)); + if (ret < 0) + ctx->error = ret; +} + +static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge) +{ + return container_of(bridge, struct tc358764, bridge); +} + +static int tc358764_init(struct tc358764 *ctx) +{ + u32 v = 0; + + tc358764_read(ctx, SYS_ID, &v); + if (ctx->error) + return tc358764_clear_error(ctx); + dev_info(ctx->dev, "ID: %#x\n", v); + + /* configure PPI counters */ + tc358764_write(ctx, PPI_TX_RX_TA, TTA_GET | TTA_SURE); + tc358764_write(ctx, PPI_LPTXTIMECNT, LPX_PERIOD); + tc358764_write(ctx, PPI_D0S_CLRSIPOCOUNT, 5); + tc358764_write(ctx, PPI_D1S_CLRSIPOCOUNT, 5); + tc358764_write(ctx, PPI_D2S_CLRSIPOCOUNT, 5); + tc358764_write(ctx, PPI_D3S_CLRSIPOCOUNT, 5); + + /* enable four data lanes and clock lane */ + tc358764_write(ctx, PPI_LANEENABLE, LANEENABLE_L3EN | LANEENABLE_L2EN | + LANEENABLE_L1EN | LANEENABLE_L0EN | LANEENABLE_CLEN); + tc358764_write(ctx, DSI_LANEENABLE, LANEENABLE_L3EN | LANEENABLE_L2EN | + LANEENABLE_L1EN | LANEENABLE_L0EN | LANEENABLE_CLEN); + + /* start */ + tc358764_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION); + tc358764_write(ctx, DSI_STARTDSI, DSI_RX_START); + + /* configure video path */ + tc358764_write(ctx, VP_CTRL, VP_CTRL_VSDELAY(15) | VP_CTRL_RGB888(1) | + VP_CTRL_EVTMODE(1) | VP_CTRL_HSPOL | VP_CTRL_VSPOL); + + /* reset PHY */ + tc358764_write(ctx, LV_PHY0, LV_PHY0_RST(1) | + LV_PHY0_PRBS_ON(4) | LV_PHY0_IS(2) | LV_PHY0_ND(6)); + tc358764_write(ctx, LV_PHY0, LV_PHY0_PRBS_ON(4) | LV_PHY0_IS(2) | + LV_PHY0_ND(6)); + + /* reset bridge */ + tc358764_write(ctx, SYS_RST, SYS_RST_LCD); + + /* set bit order */ + tc358764_write(ctx, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3)); + tc358764_write(ctx, LV_MX0407, LV_MX(LVI_R4, LVI_R7, LVI_R5, LVI_G0)); + tc358764_write(ctx, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_G6, LVI_G7)); + tc358764_write(ctx, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0)); + tc358764_write(ctx, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2)); + tc358764_write(ctx, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); + tc358764_write(ctx, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6)); + tc358764_write(ctx, LV_CFG, LV_CFG_CLKPOL2 | LV_CFG_CLKPOL1 | + LV_CFG_LVEN); + + return tc358764_clear_error(ctx); +} + +static void tc358764_reset(struct tc358764 *ctx) +{ + gpiod_set_value(ctx->gpio_reset, 1); + usleep_range(1000, 2000); + gpiod_set_value(ctx->gpio_reset, 0); + usleep_range(1000, 2000); +} + +static void tc358764_post_disable(struct drm_bridge *bridge) +{ + struct tc358764 *ctx = bridge_to_tc358764(bridge); + int ret; + + tc358764_reset(ctx); + usleep_range(10000, 15000); + ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) + dev_err(ctx->dev, "error disabling regulators (%d)\n", ret); +} + +static void tc358764_pre_enable(struct drm_bridge *bridge) +{ + struct tc358764 *ctx = bridge_to_tc358764(bridge); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) + dev_err(ctx->dev, "error enabling regulators (%d)\n", ret); + usleep_range(10000, 15000); + tc358764_reset(ctx); + ret = tc358764_init(ctx); + if (ret < 0) + dev_err(ctx->dev, "error initializing bridge (%d)\n", ret); +} + +static int tc358764_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct tc358764 *ctx = bridge_to_tc358764(bridge); + + return drm_bridge_attach(bridge->encoder, ctx->next_bridge, bridge, flags); +} + +static const struct drm_bridge_funcs tc358764_bridge_funcs = { + .post_disable = tc358764_post_disable, + .pre_enable = tc358764_pre_enable, + .attach = tc358764_attach, +}; + +static int tc358764_parse_dt(struct tc358764 *ctx) +{ + struct device *dev = ctx->dev; + + ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->gpio_reset)) { + dev_err(dev, "no reset GPIO pin provided\n"); + return PTR_ERR(ctx->gpio_reset); + } + + ctx->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); + if (IS_ERR(ctx->next_bridge)) + return PTR_ERR(ctx->next_bridge); + + return 0; +} + +static int tc358764_configure_regulators(struct tc358764 *ctx) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(ctx->supplies); ++i) + ctx->supplies[i].supply = tc358764_supplies[i]; + + ret = devm_regulator_bulk_get(ctx->dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + dev_err(ctx->dev, "failed to get regulators: %d\n", ret); + + return ret; +} + +static int tc358764_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct tc358764 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(struct tc358764), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mipi_dsi_set_drvdata(dsi, ctx); + + ctx->dev = dev; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST + | MIPI_DSI_MODE_VIDEO_AUTO_VERT | MIPI_DSI_MODE_LPM; + + ret = tc358764_parse_dt(ctx); + if (ret < 0) + return ret; + + ret = tc358764_configure_regulators(ctx); + if (ret < 0) + return ret; + + ctx->bridge.funcs = &tc358764_bridge_funcs; + ctx->bridge.of_node = dev->of_node; + + drm_bridge_add(&ctx->bridge); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_bridge_remove(&ctx->bridge); + dev_err(dev, "failed to attach dsi\n"); + } + + return ret; +} + +static void tc358764_remove(struct mipi_dsi_device *dsi) +{ + struct tc358764 *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_bridge_remove(&ctx->bridge); +} + +static const struct of_device_id tc358764_of_match[] = { + { .compatible = "toshiba,tc358764" }, + { } +}; +MODULE_DEVICE_TABLE(of, tc358764_of_match); + +static struct mipi_dsi_driver tc358764_driver = { + .probe = tc358764_probe, + .remove = tc358764_remove, + .driver = { + .name = "tc358764", + .owner = THIS_MODULE, + .of_match_table = tc358764_of_match, + }, +}; +module_mipi_dsi_driver(tc358764_driver); + +MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); +MODULE_AUTHOR("Maciej Purski <m.purski@samsung.com>"); +MODULE_DESCRIPTION("MIPI-DSI based Driver for TC358764 DSI/LVDS Bridge"); +MODULE_LICENSE("GPL v2"); |