Files
thead-uboot/drivers/video/light/dw_dsi_light.c
2022-09-13 11:04:33 +08:00

188 lines
4.0 KiB
C

// SPDX-License-Identifier: GPL-2.0+
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <dm/lists.h>
#include <dsi_host.h>
#include <generic-phy.h>
#include <mipi_dsi.h>
#include <panel.h>
#include <reset.h>
#include <video.h>
#include <video_bridge.h>
struct light_dw_dsi_priv {
struct mipi_dsi_device dsi;
fdt_addr_t base;
struct udevice *panel;
struct udevice *dsi_host;
struct phy dphy;
struct clk pix_clk;
};
#define dsi_device_to_priv(d) container_of(d, struct light_dw_dsi_priv, dsi)
static int light_dw_dphy_init(void *priv_data)
{
int ret;
struct mipi_dsi_device *dsi = priv_data;
struct light_dw_dsi_priv *priv = dsi_device_to_priv(dsi);
ret = generic_phy_reset(&priv->dphy);
if (ret) {
pr_err("reset dphy failed: %d\n", ret);
return ret;
}
ret = generic_phy_init(&priv->dphy);
if (ret) {
pr_err("init dphy failed: %d\n", ret);
return ret;
}
ret = generic_phy_power_on(&priv->dphy);
if (ret) {
pr_err("power on dphy failed: %d\n", ret);
return ret;
}
return 0;
}
static int light_dw_dphy_get_lane_mbps(void *priv_data,
struct display_timing *timings,
u32 lanes, u32 format, unsigned int *lane_mbps)
{
/* TODO */
*lane_mbps = 450;
return 0;
}
static void light_dw_dphy_post_set_mode(void *priv_data, unsigned long mode_flags)
{
}
static const struct mipi_dsi_phy_ops light_dw_dphy_ops = {
.init = light_dw_dphy_init,
.get_lane_mbps = light_dw_dphy_get_lane_mbps,
.post_set_mode = light_dw_dphy_post_set_mode,
};
static int light_dw_dsi_attach(struct udevice *dev)
{
int ret;
struct display_timing timings;
struct light_dw_dsi_priv *priv = dev_get_priv(dev);
struct mipi_dsi_device *dsi = &priv->dsi;
struct mipi_dsi_panel_plat *mplat;
ret = uclass_first_device_err(UCLASS_PANEL, &priv->panel);
if (ret) {
dev_err(dev, "get panel device err : %d\n", ret);
return ret;
}
mplat = dev_get_platdata(priv->panel);
mplat->device = dsi;
ret = panel_get_display_timing(priv->panel, &timings);
if (ret) {
dev_err(dev, "failed to get panel timing : %d\n", ret);
return ret;
}
ret = uclass_first_device_err(UCLASS_DSI_HOST, &priv->dsi_host);
if (ret) {
dev_err(dev, "No video dsi host detected : %d\n", ret);
return ret;
}
/* TODO: max data lanes */
ret = dsi_host_init(priv->dsi_host, dsi, &timings,
4, &light_dw_dphy_ops);
if (ret) {
dev_err(dev, "failed to initialize DW DSI host : %d\n", ret);
return ret;
}
return 0;
}
static int light_dw_dsi_set_backlight(struct udevice *dev, int percent)
{
int ret;
struct light_dw_dsi_priv *priv = dev_get_priv(dev);
ret = panel_enable_backlight(priv->panel);
if (ret) {
dev_err(dev, "enable panel %s backlight err : %d\n",
priv->panel->name, ret);
return ret;
}
ret = dsi_host_enable(priv->dsi_host);
if (ret) {
dev_err(dev, "failed to enable DW DSI host : %d\n", ret);
return ret;
}
return 0;
}
struct video_bridge_ops light_dw_dsi_ops = {
.attach = light_dw_dsi_attach,
.set_backlight = light_dw_dsi_set_backlight,
};
static int light_dw_dsi_ofdata_to_platdata(struct udevice *dev)
{
int ret;
struct light_dw_dsi_priv *priv = dev_get_priv(dev);
ret = generic_phy_get_by_name(dev, "dphy", &priv->dphy);
if (ret) {
dev_err(dev, "Unable to get MIPI dphy: %d\n", ret);
return ret;
}
ret = clk_get_by_name(dev, "pix-clk", &priv->pix_clk);
if (ret) {
dev_err(dev, "failed to get pixel clock: %d\n", ret);
return ret;
}
return 0;
}
static int light_dw_dsi_probe(struct udevice *dev)
{
/* TODO: enable power & clk */
/* TODO: get max lanes from dtb or driver data */
return 0;
}
static int light_dw_dsi_remove(struct udevice *dev)
{
return 0;
}
static const struct udevice_id light_dw_dsi_ids[] = {
{ .compatible = "thead,light-dsi-bridge" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(light_dw_dsi) = {
.name = "light-dw-dsi",
.id = UCLASS_VIDEO_BRIDGE,
.of_match = light_dw_dsi_ids,
.probe = light_dw_dsi_probe,
.remove = light_dw_dsi_remove,
.ops = &light_dw_dsi_ops,
.ofdata_to_platdata = light_dw_dsi_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct light_dw_dsi_priv),
};