root/drivers/gpu/drm/bridge/adv7511/adv7533.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. adv7511_dsi_config_timing_gen
  2. adv7533_dsi_power_on
  3. adv7533_dsi_power_off
  4. adv7533_mode_set
  5. adv7533_patch_registers
  6. adv7533_patch_cec_registers
  7. adv7533_attach_dsi
  8. adv7533_detach_dsi
  9. adv7533_parse_dt

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
   4  */
   5 
   6 #include <linux/of_graph.h>
   7 
   8 #include "adv7511.h"
   9 
  10 static const struct reg_sequence adv7533_fixed_registers[] = {
  11         { 0x16, 0x20 },
  12         { 0x9a, 0xe0 },
  13         { 0xba, 0x70 },
  14         { 0xde, 0x82 },
  15         { 0xe4, 0x40 },
  16         { 0xe5, 0x80 },
  17 };
  18 
  19 static const struct reg_sequence adv7533_cec_fixed_registers[] = {
  20         { 0x15, 0xd0 },
  21         { 0x17, 0xd0 },
  22         { 0x24, 0x20 },
  23         { 0x57, 0x11 },
  24         { 0x05, 0xc8 },
  25 };
  26 
  27 static void adv7511_dsi_config_timing_gen(struct adv7511 *adv)
  28 {
  29         struct mipi_dsi_device *dsi = adv->dsi;
  30         struct drm_display_mode *mode = &adv->curr_mode;
  31         unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
  32         u8 clock_div_by_lanes[] = { 6, 4, 3 };  /* 2, 3, 4 lanes */
  33 
  34         hsw = mode->hsync_end - mode->hsync_start;
  35         hfp = mode->hsync_start - mode->hdisplay;
  36         hbp = mode->htotal - mode->hsync_end;
  37         vsw = mode->vsync_end - mode->vsync_start;
  38         vfp = mode->vsync_start - mode->vdisplay;
  39         vbp = mode->vtotal - mode->vsync_end;
  40 
  41         /* set pixel clock divider mode */
  42         regmap_write(adv->regmap_cec, 0x16,
  43                      clock_div_by_lanes[dsi->lanes - 2] << 3);
  44 
  45         /* horizontal porch params */
  46         regmap_write(adv->regmap_cec, 0x28, mode->htotal >> 4);
  47         regmap_write(adv->regmap_cec, 0x29, (mode->htotal << 4) & 0xff);
  48         regmap_write(adv->regmap_cec, 0x2a, hsw >> 4);
  49         regmap_write(adv->regmap_cec, 0x2b, (hsw << 4) & 0xff);
  50         regmap_write(adv->regmap_cec, 0x2c, hfp >> 4);
  51         regmap_write(adv->regmap_cec, 0x2d, (hfp << 4) & 0xff);
  52         regmap_write(adv->regmap_cec, 0x2e, hbp >> 4);
  53         regmap_write(adv->regmap_cec, 0x2f, (hbp << 4) & 0xff);
  54 
  55         /* vertical porch params */
  56         regmap_write(adv->regmap_cec, 0x30, mode->vtotal >> 4);
  57         regmap_write(adv->regmap_cec, 0x31, (mode->vtotal << 4) & 0xff);
  58         regmap_write(adv->regmap_cec, 0x32, vsw >> 4);
  59         regmap_write(adv->regmap_cec, 0x33, (vsw << 4) & 0xff);
  60         regmap_write(adv->regmap_cec, 0x34, vfp >> 4);
  61         regmap_write(adv->regmap_cec, 0x35, (vfp << 4) & 0xff);
  62         regmap_write(adv->regmap_cec, 0x36, vbp >> 4);
  63         regmap_write(adv->regmap_cec, 0x37, (vbp << 4) & 0xff);
  64 }
  65 
  66 void adv7533_dsi_power_on(struct adv7511 *adv)
  67 {
  68         struct mipi_dsi_device *dsi = adv->dsi;
  69 
  70         if (adv->use_timing_gen)
  71                 adv7511_dsi_config_timing_gen(adv);
  72 
  73         /* set number of dsi lanes */
  74         regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
  75 
  76         if (adv->use_timing_gen) {
  77                 /* reset internal timing generator */
  78                 regmap_write(adv->regmap_cec, 0x27, 0xcb);
  79                 regmap_write(adv->regmap_cec, 0x27, 0x8b);
  80                 regmap_write(adv->regmap_cec, 0x27, 0xcb);
  81         } else {
  82                 /* disable internal timing generator */
  83                 regmap_write(adv->regmap_cec, 0x27, 0x0b);
  84         }
  85 
  86         /* enable hdmi */
  87         regmap_write(adv->regmap_cec, 0x03, 0x89);
  88         /* disable test mode */
  89         regmap_write(adv->regmap_cec, 0x55, 0x00);
  90 
  91         regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers,
  92                               ARRAY_SIZE(adv7533_cec_fixed_registers));
  93 }
  94 
  95 void adv7533_dsi_power_off(struct adv7511 *adv)
  96 {
  97         /* disable hdmi */
  98         regmap_write(adv->regmap_cec, 0x03, 0x0b);
  99         /* disable internal timing generator */
 100         regmap_write(adv->regmap_cec, 0x27, 0x0b);
 101 }
 102 
 103 void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode)
 104 {
 105         struct mipi_dsi_device *dsi = adv->dsi;
 106         int lanes, ret;
 107 
 108         if (adv->num_dsi_lanes != 4)
 109                 return;
 110 
 111         if (mode->clock > 80000)
 112                 lanes = 4;
 113         else
 114                 lanes = 3;
 115 
 116         if (lanes != dsi->lanes) {
 117                 mipi_dsi_detach(dsi);
 118                 dsi->lanes = lanes;
 119                 ret = mipi_dsi_attach(dsi);
 120                 if (ret)
 121                         dev_err(&dsi->dev, "failed to change host lanes\n");
 122         }
 123 }
 124 
 125 int adv7533_patch_registers(struct adv7511 *adv)
 126 {
 127         return regmap_register_patch(adv->regmap,
 128                                      adv7533_fixed_registers,
 129                                      ARRAY_SIZE(adv7533_fixed_registers));
 130 }
 131 
 132 int adv7533_patch_cec_registers(struct adv7511 *adv)
 133 {
 134         return regmap_register_patch(adv->regmap_cec,
 135                                     adv7533_cec_fixed_registers,
 136                                     ARRAY_SIZE(adv7533_cec_fixed_registers));
 137 }
 138 
 139 int adv7533_attach_dsi(struct adv7511 *adv)
 140 {
 141         struct device *dev = &adv->i2c_main->dev;
 142         struct mipi_dsi_host *host;
 143         struct mipi_dsi_device *dsi;
 144         int ret = 0;
 145         const struct mipi_dsi_device_info info = { .type = "adv7533",
 146                                                    .channel = 0,
 147                                                    .node = NULL,
 148                                                  };
 149 
 150         host = of_find_mipi_dsi_host_by_node(adv->host_node);
 151         if (!host) {
 152                 dev_err(dev, "failed to find dsi host\n");
 153                 return -EPROBE_DEFER;
 154         }
 155 
 156         dsi = mipi_dsi_device_register_full(host, &info);
 157         if (IS_ERR(dsi)) {
 158                 dev_err(dev, "failed to create dsi device\n");
 159                 ret = PTR_ERR(dsi);
 160                 goto err_dsi_device;
 161         }
 162 
 163         adv->dsi = dsi;
 164 
 165         dsi->lanes = adv->num_dsi_lanes;
 166         dsi->format = MIPI_DSI_FMT_RGB888;
 167         dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
 168                           MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
 169 
 170         ret = mipi_dsi_attach(dsi);
 171         if (ret < 0) {
 172                 dev_err(dev, "failed to attach dsi to host\n");
 173                 goto err_dsi_attach;
 174         }
 175 
 176         return 0;
 177 
 178 err_dsi_attach:
 179         mipi_dsi_device_unregister(dsi);
 180 err_dsi_device:
 181         return ret;
 182 }
 183 
 184 void adv7533_detach_dsi(struct adv7511 *adv)
 185 {
 186         mipi_dsi_detach(adv->dsi);
 187         mipi_dsi_device_unregister(adv->dsi);
 188 }
 189 
 190 int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
 191 {
 192         u32 num_lanes;
 193 
 194         of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
 195 
 196         if (num_lanes < 1 || num_lanes > 4)
 197                 return -EINVAL;
 198 
 199         adv->num_dsi_lanes = num_lanes;
 200 
 201         adv->host_node = of_graph_get_remote_node(np, 0, 0);
 202         if (!adv->host_node)
 203                 return -ENODEV;
 204 
 205         of_node_put(adv->host_node);
 206 
 207         adv->use_timing_gen = !of_property_read_bool(np,
 208                                                 "adi,disable-timing-generator");
 209 
 210         /* TODO: Check if these need to be parsed by DT or not */
 211         adv->rgb = true;
 212         adv->embedded_sync = false;
 213 
 214         return 0;
 215 }

/* [<][>][^][v][top][bottom][index][help] */