Skip to content

Commit 9fd37b6

Browse files
jrripplegregkh
authored andcommitted
drm/bridge: ti-sn65dsi86: Add support for DisplayPort mode with HPD
commit 9133bc3 upstream. Add support for DisplayPort to the bridge, which entails the following: - Get and use an interrupt for HPD; - Properly clear all status bits in the interrupt handler; Signed-off-by: John Ripple <john.ripple@keysight.com> Reviewed-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Douglas Anderson <dianders@chromium.org> Link: https://lore.kernel.org/r/20250915174543.2564994-1-john.ripple@keysight.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 24fda22 commit 9fd37b6

1 file changed

Lines changed: 112 additions & 0 deletions

File tree

drivers/gpu/drm/bridge/ti-sn65dsi86.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,21 @@
106106
#define SN_PWM_EN_INV_REG 0xA5
107107
#define SN_PWM_INV_MASK BIT(0)
108108
#define SN_PWM_EN_MASK BIT(1)
109+
110+
#define SN_IRQ_EN_REG 0xE0
111+
#define IRQ_EN BIT(0)
112+
113+
#define SN_IRQ_EVENTS_EN_REG 0xE6
114+
#define HPD_INSERTION_EN BIT(1)
115+
#define HPD_REMOVAL_EN BIT(2)
116+
109117
#define SN_AUX_CMD_STATUS_REG 0xF4
110118
#define AUX_IRQ_STATUS_AUX_RPLY_TOUT BIT(3)
111119
#define AUX_IRQ_STATUS_AUX_SHORT BIT(5)
112120
#define AUX_IRQ_STATUS_NAT_I2C_FAIL BIT(6)
121+
#define SN_IRQ_STATUS_REG 0xF5
122+
#define HPD_REMOVAL_STATUS BIT(2)
123+
#define HPD_INSERTION_STATUS BIT(1)
113124

114125
#define MIN_DSI_CLK_FREQ_MHZ 40
115126

@@ -152,7 +163,9 @@
152163
* @ln_assign: Value to program to the LN_ASSIGN register.
153164
* @ln_polrs: Value for the 4-bit LN_POLRS field of SN_ENH_FRAME_REG.
154165
* @comms_enabled: If true then communication over the aux channel is enabled.
166+
* @hpd_enabled: If true then HPD events are enabled.
155167
* @comms_mutex: Protects modification of comms_enabled.
168+
* @hpd_mutex: Protects modification of hpd_enabled.
156169
*
157170
* @gchip: If we expose our GPIOs, this is used.
158171
* @gchip_output: A cache of whether we've set GPIOs to output. This
@@ -190,7 +203,9 @@ struct ti_sn65dsi86 {
190203
u8 ln_assign;
191204
u8 ln_polrs;
192205
bool comms_enabled;
206+
bool hpd_enabled;
193207
struct mutex comms_mutex;
208+
struct mutex hpd_mutex;
194209

195210
#if defined(CONFIG_OF_GPIO)
196211
struct gpio_chip gchip;
@@ -221,6 +236,23 @@ static const struct regmap_config ti_sn65dsi86_regmap_config = {
221236
.max_register = 0xFF,
222237
};
223238

239+
static int ti_sn65dsi86_read_u8(struct ti_sn65dsi86 *pdata, unsigned int reg,
240+
u8 *val)
241+
{
242+
int ret;
243+
unsigned int reg_val;
244+
245+
ret = regmap_read(pdata->regmap, reg, &reg_val);
246+
if (ret) {
247+
dev_err(pdata->dev, "fail to read raw reg %#x: %d\n",
248+
reg, ret);
249+
return ret;
250+
}
251+
*val = (u8)reg_val;
252+
253+
return 0;
254+
}
255+
224256
static int __maybe_unused ti_sn65dsi86_read_u16(struct ti_sn65dsi86 *pdata,
225257
unsigned int reg, u16 *val)
226258
{
@@ -379,6 +411,7 @@ static void ti_sn65dsi86_disable_comms(struct ti_sn65dsi86 *pdata)
379411
static int __maybe_unused ti_sn65dsi86_resume(struct device *dev)
380412
{
381413
struct ti_sn65dsi86 *pdata = dev_get_drvdata(dev);
414+
const struct i2c_client *client = to_i2c_client(pdata->dev);
382415
int ret;
383416

384417
ret = regulator_bulk_enable(SN_REGULATOR_SUPPLY_NUM, pdata->supplies);
@@ -413,6 +446,13 @@ static int __maybe_unused ti_sn65dsi86_resume(struct device *dev)
413446
if (pdata->refclk)
414447
ti_sn65dsi86_enable_comms(pdata, NULL);
415448

449+
if (client->irq) {
450+
ret = regmap_update_bits(pdata->regmap, SN_IRQ_EN_REG, IRQ_EN,
451+
IRQ_EN);
452+
if (ret)
453+
dev_err(pdata->dev, "Failed to enable IRQ events: %d\n", ret);
454+
}
455+
416456
return ret;
417457
}
418458

@@ -1211,6 +1251,8 @@ static void ti_sn65dsi86_debugfs_init(struct drm_bridge *bridge, struct dentry *
12111251
static void ti_sn_bridge_hpd_enable(struct drm_bridge *bridge)
12121252
{
12131253
struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
1254+
const struct i2c_client *client = to_i2c_client(pdata->dev);
1255+
int ret;
12141256

12151257
/*
12161258
* Device needs to be powered on before reading the HPD state
@@ -1219,11 +1261,35 @@ static void ti_sn_bridge_hpd_enable(struct drm_bridge *bridge)
12191261
*/
12201262

12211263
pm_runtime_get_sync(pdata->dev);
1264+
1265+
mutex_lock(&pdata->hpd_mutex);
1266+
pdata->hpd_enabled = true;
1267+
mutex_unlock(&pdata->hpd_mutex);
1268+
1269+
if (client->irq) {
1270+
ret = regmap_set_bits(pdata->regmap, SN_IRQ_EVENTS_EN_REG,
1271+
HPD_REMOVAL_EN | HPD_INSERTION_EN);
1272+
if (ret)
1273+
dev_err(pdata->dev, "Failed to enable HPD events: %d\n", ret);
1274+
}
12221275
}
12231276

12241277
static void ti_sn_bridge_hpd_disable(struct drm_bridge *bridge)
12251278
{
12261279
struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
1280+
const struct i2c_client *client = to_i2c_client(pdata->dev);
1281+
int ret;
1282+
1283+
if (client->irq) {
1284+
ret = regmap_clear_bits(pdata->regmap, SN_IRQ_EVENTS_EN_REG,
1285+
HPD_REMOVAL_EN | HPD_INSERTION_EN);
1286+
if (ret)
1287+
dev_err(pdata->dev, "Failed to disable HPD events: %d\n", ret);
1288+
}
1289+
1290+
mutex_lock(&pdata->hpd_mutex);
1291+
pdata->hpd_enabled = false;
1292+
mutex_unlock(&pdata->hpd_mutex);
12271293

12281294
pm_runtime_put_autosuspend(pdata->dev);
12291295
}
@@ -1309,6 +1375,41 @@ static int ti_sn_bridge_parse_dsi_host(struct ti_sn65dsi86 *pdata)
13091375
return 0;
13101376
}
13111377

1378+
static irqreturn_t ti_sn_bridge_interrupt(int irq, void *private)
1379+
{
1380+
struct ti_sn65dsi86 *pdata = private;
1381+
struct drm_device *dev = pdata->bridge.dev;
1382+
u8 status;
1383+
int ret;
1384+
bool hpd_event;
1385+
1386+
ret = ti_sn65dsi86_read_u8(pdata, SN_IRQ_STATUS_REG, &status);
1387+
if (ret) {
1388+
dev_err(pdata->dev, "Failed to read IRQ status: %d\n", ret);
1389+
return IRQ_NONE;
1390+
}
1391+
1392+
hpd_event = status & (HPD_REMOVAL_STATUS | HPD_INSERTION_STATUS);
1393+
1394+
dev_dbg(pdata->dev, "(SN_IRQ_STATUS_REG = %#x)\n", status);
1395+
if (!status)
1396+
return IRQ_NONE;
1397+
1398+
ret = regmap_write(pdata->regmap, SN_IRQ_STATUS_REG, status);
1399+
if (ret) {
1400+
dev_err(pdata->dev, "Failed to clear IRQ status: %d\n", ret);
1401+
return IRQ_NONE;
1402+
}
1403+
1404+
/* Only send the HPD event if we are bound with a device. */
1405+
mutex_lock(&pdata->hpd_mutex);
1406+
if (pdata->hpd_enabled && hpd_event)
1407+
drm_kms_helper_hotplug_event(dev);
1408+
mutex_unlock(&pdata->hpd_mutex);
1409+
1410+
return IRQ_HANDLED;
1411+
}
1412+
13121413
static int ti_sn_bridge_probe(struct auxiliary_device *adev,
13131414
const struct auxiliary_device_id *id)
13141415
{
@@ -1933,6 +2034,7 @@ static int ti_sn65dsi86_probe(struct i2c_client *client)
19332034
dev_set_drvdata(dev, pdata);
19342035
pdata->dev = dev;
19352036

2037+
mutex_init(&pdata->hpd_mutex);
19362038
mutex_init(&pdata->comms_mutex);
19372039

19382040
pdata->regmap = devm_regmap_init_i2c(client,
@@ -1973,6 +2075,16 @@ static int ti_sn65dsi86_probe(struct i2c_client *client)
19732075
if (strncmp(id_buf, "68ISD ", ARRAY_SIZE(id_buf)))
19742076
return dev_err_probe(dev, -EOPNOTSUPP, "unsupported device id\n");
19752077

2078+
if (client->irq) {
2079+
ret = devm_request_threaded_irq(pdata->dev, client->irq, NULL,
2080+
ti_sn_bridge_interrupt,
2081+
IRQF_ONESHOT,
2082+
dev_name(pdata->dev), pdata);
2083+
2084+
if (ret)
2085+
return dev_err_probe(dev, ret, "failed to request interrupt\n");
2086+
}
2087+
19762088
/*
19772089
* Break ourselves up into a collection of aux devices. The only real
19782090
* motiviation here is to solve the chicken-and-egg problem of probe

0 commit comments

Comments
 (0)