Path: blob/master/drivers/gpu/drm/bridge/adv7511/adv7533.c
26516 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (c) 2016, The Linux Foundation. All rights reserved.3*/45#include <linux/of_graph.h>67#include "adv7511.h"89static const struct reg_sequence adv7533_fixed_registers[] = {10{ 0x16, 0x20 },11{ 0x9a, 0xe0 },12{ 0xba, 0x70 },13{ 0xde, 0x82 },14{ 0xe4, 0x40 },15{ 0xe5, 0x80 },16};1718static const struct reg_sequence adv7533_cec_fixed_registers[] = {19{ 0x15, 0xd0 },20{ 0x17, 0xd0 },21{ 0x24, 0x20 },22{ 0x57, 0x11 },23{ 0x05, 0xc8 },24};2526void adv7533_dsi_config_timing_gen(struct adv7511 *adv)27{28struct mipi_dsi_device *dsi = adv->dsi;29struct drm_display_mode *mode = &adv->curr_mode;30unsigned int hsw, hfp, hbp, vsw, vfp, vbp;31static const u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */3233hsw = mode->hsync_end - mode->hsync_start;34hfp = mode->hsync_start - mode->hdisplay;35hbp = mode->htotal - mode->hsync_end;36vsw = mode->vsync_end - mode->vsync_start;37vfp = mode->vsync_start - mode->vdisplay;38vbp = mode->vtotal - mode->vsync_end;3940/* set pixel clock divider mode */41regmap_write(adv->regmap_cec, 0x16,42clock_div_by_lanes[dsi->lanes - 2] << 3);4344/* horizontal porch params */45regmap_write(adv->regmap_cec, 0x28, mode->htotal >> 4);46regmap_write(adv->regmap_cec, 0x29, (mode->htotal << 4) & 0xff);47regmap_write(adv->regmap_cec, 0x2a, hsw >> 4);48regmap_write(adv->regmap_cec, 0x2b, (hsw << 4) & 0xff);49regmap_write(adv->regmap_cec, 0x2c, hfp >> 4);50regmap_write(adv->regmap_cec, 0x2d, (hfp << 4) & 0xff);51regmap_write(adv->regmap_cec, 0x2e, hbp >> 4);52regmap_write(adv->regmap_cec, 0x2f, (hbp << 4) & 0xff);5354/* vertical porch params */55regmap_write(adv->regmap_cec, 0x30, mode->vtotal >> 4);56regmap_write(adv->regmap_cec, 0x31, (mode->vtotal << 4) & 0xff);57regmap_write(adv->regmap_cec, 0x32, vsw >> 4);58regmap_write(adv->regmap_cec, 0x33, (vsw << 4) & 0xff);59regmap_write(adv->regmap_cec, 0x34, vfp >> 4);60regmap_write(adv->regmap_cec, 0x35, (vfp << 4) & 0xff);61regmap_write(adv->regmap_cec, 0x36, vbp >> 4);62regmap_write(adv->regmap_cec, 0x37, (vbp << 4) & 0xff);63}6465void adv7533_dsi_power_on(struct adv7511 *adv)66{67struct mipi_dsi_device *dsi = adv->dsi;6869/* set number of dsi lanes */70regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);7172if (adv->use_timing_gen) {73/* reset internal timing generator */74regmap_write(adv->regmap_cec, 0x27, 0xcb);75regmap_write(adv->regmap_cec, 0x27, 0x8b);76regmap_write(adv->regmap_cec, 0x27, 0xcb);77} else {78/* disable internal timing generator */79regmap_write(adv->regmap_cec, 0x27, 0x0b);80}8182/* enable hdmi */83regmap_write(adv->regmap_cec, 0x03, 0x89);84/* disable test mode */85regmap_write(adv->regmap_cec, 0x55, 0x00);8687regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers,88ARRAY_SIZE(adv7533_cec_fixed_registers));89}9091void adv7533_dsi_power_off(struct adv7511 *adv)92{93/* disable hdmi */94regmap_write(adv->regmap_cec, 0x03, 0x0b);95/* disable internal timing generator */96regmap_write(adv->regmap_cec, 0x27, 0x0b);97}9899enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv,100const struct drm_display_mode *mode)101{102struct mipi_dsi_device *dsi = adv->dsi;103u8 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);104105/* Check max clock for each lane */106if (mode->clock * bpp > adv->info->max_lane_freq_khz * adv->num_dsi_lanes)107return MODE_CLOCK_HIGH;108109return MODE_OK;110}111112int adv7533_patch_registers(struct adv7511 *adv)113{114return regmap_register_patch(adv->regmap,115adv7533_fixed_registers,116ARRAY_SIZE(adv7533_fixed_registers));117}118119int adv7533_patch_cec_registers(struct adv7511 *adv)120{121return regmap_register_patch(adv->regmap_cec,122adv7533_cec_fixed_registers,123ARRAY_SIZE(adv7533_cec_fixed_registers));124}125126int adv7533_attach_dsi(struct adv7511 *adv)127{128struct device *dev = &adv->i2c_main->dev;129struct mipi_dsi_host *host;130struct mipi_dsi_device *dsi;131int ret = 0;132const struct mipi_dsi_device_info info = { .type = "adv7533",133.channel = 0,134.node = NULL,135};136137host = of_find_mipi_dsi_host_by_node(adv->host_node);138if (!host)139return dev_err_probe(dev, -EPROBE_DEFER,140"failed to find dsi host\n");141142dsi = devm_mipi_dsi_device_register_full(dev, host, &info);143if (IS_ERR(dsi))144return dev_err_probe(dev, PTR_ERR(dsi),145"failed to create dsi device\n");146147adv->dsi = dsi;148149dsi->lanes = adv->num_dsi_lanes;150dsi->format = MIPI_DSI_FMT_RGB888;151dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |152MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;153154ret = devm_mipi_dsi_attach(dev, dsi);155if (ret < 0)156return dev_err_probe(dev, ret, "failed to attach dsi to host\n");157158return 0;159}160161int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)162{163u32 num_lanes;164165of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);166167if (num_lanes < 2 || num_lanes > 4)168return -EINVAL;169170adv->num_dsi_lanes = num_lanes;171172adv->host_node = of_graph_get_remote_node(np, 0, 0);173if (!adv->host_node)174return -ENODEV;175176adv->use_timing_gen = !of_property_read_bool(np,177"adi,disable-timing-generator");178179/* TODO: Check if these need to be parsed by DT or not */180adv->rgb = true;181adv->embedded_sync = false;182183return 0;184}185186187