// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
*/
#include <linux/of_graph.h>
#include "adv7511.h"
static const struct reg_sequence adv7533_fixed_registers[] = {
{ 0 x16, 0 x20 },
{ 0 x9a, 0 xe0 },
{ 0 xba, 0 x70 },
{ 0 xde, 0 x82 },
{ 0 xe4, 0 x40 },
{ 0 xe5, 0 x80 },
};
static const struct reg_sequence adv7533_cec_fixed_registers[] = {
{ 0 x15, 0 xd0 },
{ 0 x17, 0 xd0 },
{ 0 x24, 0 x20 },
{ 0 x57, 0 x11 },
{ 0 x05, 0 xc8 },
};
void adv7533_dsi_config_timing_gen(struct adv7511 *adv)
{
struct mipi_dsi_device *dsi = adv->dsi;
struct drm_display_mode *mode = &adv->curr_mode;
unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
static const u8 clock_div_by_lanes[] = { 6 , 4 , 3 }; /* 2, 3, 4 lanes */
hsw = mode->hsync_end - mode->hsync_start;
hfp = mode->hsync_start - mode->hdisplay;
hbp = mode->htotal - mode->hsync_end;
vsw = mode->vsync_end - mode->vsync_start;
vfp = mode->vsync_start - mode->vdisplay;
vbp = mode->vtotal - mode->vsync_end;
/* set pixel clock divider mode */
regmap_write(adv->regmap_cec, 0 x16,
clock_div_by_lanes[dsi->lanes - 2 ] << 3 );
/* horizontal porch params */
regmap_write(adv->regmap_cec, 0 x28, mode->htotal >> 4 );
regmap_write(adv->regmap_cec, 0 x29, (mode->htotal << 4 ) & 0 xff);
regmap_write(adv->regmap_cec, 0 x2a, hsw >> 4 );
regmap_write(adv->regmap_cec, 0 x2b, (hsw << 4 ) & 0 xff);
regmap_write(adv->regmap_cec, 0 x2c, hfp >> 4 );
regmap_write(adv->regmap_cec, 0 x2d, (hfp << 4 ) & 0 xff);
regmap_write(adv->regmap_cec, 0 x2e, hbp >> 4 );
regmap_write(adv->regmap_cec, 0 x2f, (hbp << 4 ) & 0 xff);
/* vertical porch params */
regmap_write(adv->regmap_cec, 0 x30, mode->vtotal >> 4 );
regmap_write(adv->regmap_cec, 0 x31, (mode->vtotal << 4 ) & 0 xff);
regmap_write(adv->regmap_cec, 0 x32, vsw >> 4 );
regmap_write(adv->regmap_cec, 0 x33, (vsw << 4 ) & 0 xff);
regmap_write(adv->regmap_cec, 0 x34, vfp >> 4 );
regmap_write(adv->regmap_cec, 0 x35, (vfp << 4 ) & 0 xff);
regmap_write(adv->regmap_cec, 0 x36, vbp >> 4 );
regmap_write(adv->regmap_cec, 0 x37, (vbp << 4 ) & 0 xff);
}
void adv7533_dsi_power_on(struct adv7511 *adv)
{
struct mipi_dsi_device *dsi = adv->dsi;
/* set number of dsi lanes */
regmap_write(adv->regmap_cec, 0 x1c, dsi->lanes << 4 );
if (adv->use_timing_gen) {
/* reset internal timing generator */
regmap_write(adv->regmap_cec, 0 x27, 0 xcb);
regmap_write(adv->regmap_cec, 0 x27, 0 x8b);
regmap_write(adv->regmap_cec, 0 x27, 0 xcb);
} else {
/* disable internal timing generator */
regmap_write(adv->regmap_cec, 0 x27, 0 x0b);
}
/* enable hdmi */
regmap_write(adv->regmap_cec, 0 x03, 0 x89);
/* disable test mode */
regmap_write(adv->regmap_cec, 0 x55, 0 x00);
regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers,
ARRAY_SIZE(adv7533_cec_fixed_registers));
}
void adv7533_dsi_power_off(struct adv7511 *adv)
{
/* disable hdmi */
regmap_write(adv->regmap_cec, 0 x03, 0 x0b);
/* disable internal timing generator */
regmap_write(adv->regmap_cec, 0 x27, 0 x0b);
}
enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv,
const struct drm_display_mode *mode)
{
struct mipi_dsi_device *dsi = adv->dsi;
u8 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
/* Check max clock for each lane */
if (mode->clock * bpp > adv->info->max_lane_freq_khz * adv->num_dsi_lanes)
return MODE_CLOCK_HIGH;
return MODE_OK;
}
int adv7533_patch_registers(struct adv7511 *adv)
{
return regmap_register_patch(adv->regmap,
adv7533_fixed_registers,
ARRAY_SIZE(adv7533_fixed_registers));
}
int adv7533_patch_cec_registers(struct adv7511 *adv)
{
return regmap_register_patch(adv->regmap_cec,
adv7533_cec_fixed_registers,
ARRAY_SIZE(adv7533_cec_fixed_registers));
}
int adv7533_attach_dsi(struct adv7511 *adv)
{
struct device *dev = &adv->i2c_main->dev;
struct mipi_dsi_host *host;
struct mipi_dsi_device *dsi;
int ret = 0 ;
const struct mipi_dsi_device_info info = { .type = "adv7533" ,
.channel = 0 ,
.node = NULL,
};
host = of_find_mipi_dsi_host_by_node(adv->host_node);
if (!host)
return dev_err_probe(dev, -EPROBE_DEFER,
"failed to find dsi host\n" );
dsi = devm_mipi_dsi_device_register_full(dev, host, &info);
if (IS_ERR(dsi))
return dev_err_probe(dev, PTR_ERR(dsi),
"failed to create dsi device\n" );
adv->dsi = dsi;
dsi->lanes = adv->num_dsi_lanes;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret < 0 )
return dev_err_probe(dev, ret, "failed to attach dsi to host\n" );
return 0 ;
}
int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
{
u32 num_lanes;
of_property_read_u32(np, "adi,dsi-lanes" , &num_lanes);
if (num_lanes < 2 || num_lanes > 4 )
return -EINVAL;
adv->num_dsi_lanes = num_lanes;
adv->host_node = of_graph_get_remote_node(np, 0 , 0 );
if (!adv->host_node)
return -ENODEV;
adv->use_timing_gen = !of_property_read_bool(np,
"adi,disable-timing-generator" );
/* TODO: Check if these need to be parsed by DT or not */
adv->rgb = true ;
adv->embedded_sync = false ;
return 0 ;
}
Messung V0.5 in Prozent C=97 H=94 G=95
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland