Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/bridge/lontium-lt8713sx.c
170953 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4
*/
5
6
#include <linux/crc8.h>
7
#include <linux/firmware.h>
8
#include <linux/gpio/consumer.h>
9
#include <linux/i2c.h>
10
#include <linux/interrupt.h>
11
#include <linux/module.h>
12
#include <linux/mutex.h>
13
#include <linux/of_graph.h>
14
#include <linux/platform_device.h>
15
#include <linux/regmap.h>
16
#include <linux/regulator/consumer.h>
17
#include <linux/sizes.h>
18
#include <linux/wait.h>
19
#include <linux/workqueue.h>
20
21
#include <drm/drm_bridge.h>
22
#include <drm/drm_of.h>
23
24
#define FW_FILE "lt8713sx_fw.bin"
25
26
#define REG_PAGE_CONTROL 0xff
27
28
#define LT8713SX_PAGE_SIZE 256
29
30
DECLARE_CRC8_TABLE(lt8713sx_crc_table);
31
32
struct lt8713sx {
33
struct device *dev;
34
struct drm_bridge bridge;
35
struct drm_bridge *next_bridge;
36
37
struct regmap *regmap;
38
/* Protects all accesses to registers by stopping the on-chip MCU */
39
struct mutex ocm_lock;
40
41
struct gpio_desc *reset_gpio;
42
struct gpio_desc *enable_gpio;
43
44
struct i2c_client *client;
45
const struct firmware *fw;
46
47
u8 *fw_buffer;
48
49
u32 main_crc_value;
50
u32 bank_crc_value[17];
51
52
int bank_num;
53
};
54
55
static void lt8713sx_reset(struct lt8713sx *lt8713sx);
56
57
static const struct regmap_range lt8713sx_ranges[] = {
58
{
59
.range_min = 0x0000,
60
.range_max = 0xffff
61
},
62
};
63
64
static const struct regmap_access_table lt8713sx_table = {
65
.yes_ranges = lt8713sx_ranges,
66
.n_yes_ranges = ARRAY_SIZE(lt8713sx_ranges),
67
};
68
69
static const struct regmap_range_cfg lt8713sx_range_cfg = {
70
.name = "lt8713sx",
71
.range_min = 0x0000,
72
.range_max = 0xffff,
73
.selector_reg = REG_PAGE_CONTROL,
74
.selector_mask = 0xff,
75
.selector_shift = 0,
76
.window_start = 0,
77
.window_len = 0x100,
78
};
79
80
static const struct regmap_config lt8713sx_regmap_config = {
81
.reg_bits = 8,
82
.val_bits = 8,
83
.volatile_table = &lt8713sx_table,
84
.ranges = &lt8713sx_range_cfg,
85
.num_ranges = 1,
86
.cache_type = REGCACHE_NONE,
87
.max_register = 0xffff,
88
};
89
90
static void lt8713sx_i2c_enable(struct lt8713sx *lt8713sx)
91
{
92
regmap_write(lt8713sx->regmap, 0xe0ee, 0x01);
93
}
94
95
static void lt8713sx_i2c_disable(struct lt8713sx *lt8713sx)
96
{
97
regmap_write(lt8713sx->regmap, 0xe0ee, 0x00);
98
}
99
100
static int lt8713sx_prepare_firmware_data(struct lt8713sx *lt8713sx)
101
{
102
int ret = 0;
103
size_t sz_12k = 12 * SZ_1K;
104
105
ret = request_firmware(&lt8713sx->fw, FW_FILE, lt8713sx->dev);
106
if (ret < 0) {
107
dev_err(lt8713sx->dev, "request firmware failed\n");
108
return ret;
109
}
110
111
dev_dbg(lt8713sx->dev, "Firmware size: %zu bytes\n", lt8713sx->fw->size);
112
113
if (lt8713sx->fw->size > SZ_256K - 1) {
114
dev_err(lt8713sx->dev, "Firmware size exceeds 256KB limit\n");
115
release_firmware(lt8713sx->fw);
116
return -EINVAL;
117
}
118
119
lt8713sx->fw_buffer = kvmalloc(SZ_256K, GFP_KERNEL);
120
if (!lt8713sx->fw_buffer) {
121
release_firmware(lt8713sx->fw);
122
return -ENOMEM;
123
}
124
125
memset(lt8713sx->fw_buffer, 0xff, SZ_256K);
126
127
/* main firmware */
128
memcpy(lt8713sx->fw_buffer, lt8713sx->fw->data, SZ_64K - 1);
129
130
lt8713sx->fw_buffer[SZ_64K - 1] =
131
crc8(lt8713sx_crc_table, lt8713sx->fw_buffer, SZ_64K - 1, 0);
132
lt8713sx->main_crc_value = lt8713sx->fw_buffer[SZ_64K - 1];
133
dev_dbg(lt8713sx->dev,
134
"Main Firmware Data Crc = 0x%02X\n", lt8713sx->main_crc_value);
135
136
/* bank firmware */
137
memcpy(lt8713sx->fw_buffer + SZ_64K,
138
lt8713sx->fw->data + SZ_64K,
139
lt8713sx->fw->size - SZ_64K);
140
141
lt8713sx->bank_num = (lt8713sx->fw->size - SZ_64K + sz_12k - 1) / sz_12k;
142
dev_dbg(lt8713sx->dev, "Bank Number Total is %d.\n", lt8713sx->bank_num);
143
144
for (int i = 0; i < lt8713sx->bank_num; i++) {
145
lt8713sx->bank_crc_value[i] =
146
crc8(lt8713sx_crc_table, lt8713sx->fw_buffer + SZ_64K + i * sz_12k,
147
sz_12k, 0);
148
dev_dbg(lt8713sx->dev, "Bank number:%d; Firmware Data Crc:0x%02X\n",
149
i, lt8713sx->bank_crc_value[i]);
150
}
151
return 0;
152
}
153
154
static void lt8713sx_config_parameters(struct lt8713sx *lt8713sx)
155
{
156
regmap_write(lt8713sx->regmap, 0xe05e, 0xc1);
157
regmap_write(lt8713sx->regmap, 0xe058, 0x00);
158
regmap_write(lt8713sx->regmap, 0xe059, 0x50);
159
regmap_write(lt8713sx->regmap, 0xe05a, 0x10);
160
regmap_write(lt8713sx->regmap, 0xe05a, 0x00);
161
regmap_write(lt8713sx->regmap, 0xe058, 0x21);
162
}
163
164
static void lt8713sx_wren(struct lt8713sx *lt8713sx)
165
{
166
regmap_write(lt8713sx->regmap, 0xe103, 0xbf);
167
regmap_write(lt8713sx->regmap, 0xe103, 0xff);
168
regmap_write(lt8713sx->regmap, 0xe05a, 0x04);
169
regmap_write(lt8713sx->regmap, 0xe05a, 0x00);
170
}
171
172
static void lt8713sx_wrdi(struct lt8713sx *lt8713sx)
173
{
174
regmap_write(lt8713sx->regmap, 0xe05a, 0x08);
175
regmap_write(lt8713sx->regmap, 0xe05a, 0x00);
176
}
177
178
static void lt8713sx_fifo_reset(struct lt8713sx *lt8713sx)
179
{
180
regmap_write(lt8713sx->regmap, 0xe103, 0xbf);
181
regmap_write(lt8713sx->regmap, 0xe103, 0xff);
182
}
183
184
static void lt8713sx_disable_sram_write(struct lt8713sx *lt8713sx)
185
{
186
regmap_write(lt8713sx->regmap, 0xe055, 0x00);
187
}
188
189
static void lt8713sx_sram_to_flash(struct lt8713sx *lt8713sx)
190
{
191
regmap_write(lt8713sx->regmap, 0xe05a, 0x30);
192
regmap_write(lt8713sx->regmap, 0xe05a, 0x00);
193
}
194
195
static void lt8713sx_i2c_to_sram(struct lt8713sx *lt8713sx)
196
{
197
regmap_write(lt8713sx->regmap, 0xe055, 0x80);
198
regmap_write(lt8713sx->regmap, 0xe05e, 0xc0);
199
regmap_write(lt8713sx->regmap, 0xe058, 0x21);
200
}
201
202
static u8 lt8713sx_read_flash_status(struct lt8713sx *lt8713sx)
203
{
204
u32 flash_status = 0;
205
206
regmap_write(lt8713sx->regmap, 0xe103, 0x3f);
207
regmap_write(lt8713sx->regmap, 0xe103, 0xff);
208
209
regmap_write(lt8713sx->regmap, 0xe05e, 0x40);
210
regmap_write(lt8713sx->regmap, 0xe056, 0x05); /* opcode=read status register */
211
regmap_write(lt8713sx->regmap, 0xe055, 0x25);
212
regmap_write(lt8713sx->regmap, 0xe055, 0x01);
213
regmap_write(lt8713sx->regmap, 0xe058, 0x21);
214
215
regmap_read(lt8713sx->regmap, 0xe05f, &flash_status);
216
dev_dbg(lt8713sx->dev, "flash_status:%x\n", flash_status);
217
218
return flash_status;
219
}
220
221
static void lt8713sx_block_erase(struct lt8713sx *lt8713sx)
222
{
223
u32 i = 0;
224
u8 flash_status = 0;
225
u8 blocknum = 0x00;
226
u32 flashaddr = 0x00;
227
228
for (blocknum = 0; blocknum < 8; blocknum++) {
229
flashaddr = blocknum * SZ_32K;
230
regmap_write(lt8713sx->regmap, 0xe05a, 0x04);
231
regmap_write(lt8713sx->regmap, 0xe05a, 0x00);
232
regmap_write(lt8713sx->regmap, 0xe05b, flashaddr >> 16);
233
regmap_write(lt8713sx->regmap, 0xe05c, flashaddr >> 8);
234
regmap_write(lt8713sx->regmap, 0xe05d, flashaddr);
235
regmap_write(lt8713sx->regmap, 0xe05a, 0x01);
236
regmap_write(lt8713sx->regmap, 0xe05a, 0x00);
237
msleep(100);
238
i = 0;
239
while (1) {
240
flash_status = lt8713sx_read_flash_status(lt8713sx);
241
if ((flash_status & 0x01) == 0)
242
break;
243
244
if (i > 50)
245
break;
246
247
i++;
248
msleep(50);
249
}
250
}
251
dev_dbg(lt8713sx->dev, "erase flash done.\n");
252
}
253
254
static void lt8713sx_load_main_fw_to_sram(struct lt8713sx *lt8713sx)
255
{
256
regmap_write(lt8713sx->regmap, 0xe068, 0x00);
257
regmap_write(lt8713sx->regmap, 0xe069, 0x00);
258
regmap_write(lt8713sx->regmap, 0xe06a, 0x00);
259
regmap_write(lt8713sx->regmap, 0xe065, 0x00);
260
regmap_write(lt8713sx->regmap, 0xe066, 0xff);
261
regmap_write(lt8713sx->regmap, 0xe067, 0xff);
262
regmap_write(lt8713sx->regmap, 0xe06b, 0x00);
263
regmap_write(lt8713sx->regmap, 0xe06c, 0x00);
264
regmap_write(lt8713sx->regmap, 0xe060, 0x01);
265
msleep(200);
266
regmap_write(lt8713sx->regmap, 0xe060, 0x00);
267
}
268
269
static void lt8713sx_load_bank_fw_to_sram(struct lt8713sx *lt8713sx, u64 addr)
270
{
271
regmap_write(lt8713sx->regmap, 0xe068, ((addr & 0xff0000) >> 16));
272
regmap_write(lt8713sx->regmap, 0xe069, ((addr & 0x00ff00) >> 8));
273
regmap_write(lt8713sx->regmap, 0xe06a, (addr & 0x0000ff));
274
regmap_write(lt8713sx->regmap, 0xe065, 0x00);
275
regmap_write(lt8713sx->regmap, 0xe066, 0x30);
276
regmap_write(lt8713sx->regmap, 0xe067, 0x00);
277
regmap_write(lt8713sx->regmap, 0xe06b, 0x00);
278
regmap_write(lt8713sx->regmap, 0xe06c, 0x00);
279
regmap_write(lt8713sx->regmap, 0xe060, 0x01);
280
msleep(50);
281
regmap_write(lt8713sx->regmap, 0xe060, 0x00);
282
}
283
284
static int lt8713sx_write_data(struct lt8713sx *lt8713sx, const u8 *data, u64 filesize)
285
{
286
int page = 0, num = 0, i = 0, val;
287
288
page = (filesize % LT8713SX_PAGE_SIZE) ?
289
((filesize / LT8713SX_PAGE_SIZE) + 1) : (filesize / LT8713SX_PAGE_SIZE);
290
291
dev_dbg(lt8713sx->dev,
292
"Writing to Sram=%u pages, total size = %llu bytes\n", page, filesize);
293
294
for (num = 0; num < page; num++) {
295
dev_dbg(lt8713sx->dev, "page[%d]\n", num);
296
lt8713sx_i2c_to_sram(lt8713sx);
297
298
for (i = 0; i < LT8713SX_PAGE_SIZE; i++) {
299
if ((num * LT8713SX_PAGE_SIZE + i) < filesize)
300
val = *(data + (num * LT8713SX_PAGE_SIZE + i));
301
else
302
val = 0xff;
303
regmap_write(lt8713sx->regmap, 0xe059, val);
304
}
305
306
lt8713sx_wren(lt8713sx);
307
lt8713sx_sram_to_flash(lt8713sx);
308
}
309
310
lt8713sx_wrdi(lt8713sx);
311
lt8713sx_disable_sram_write(lt8713sx);
312
313
return 0;
314
}
315
316
static void lt8713sx_main_upgrade_result(struct lt8713sx *lt8713sx)
317
{
318
u32 main_crc_result;
319
320
regmap_read(lt8713sx->regmap, 0xe023, &main_crc_result);
321
322
dev_dbg(lt8713sx->dev, "Main CRC HW: 0x%02X\n", main_crc_result);
323
dev_dbg(lt8713sx->dev, "Main CRC FW: 0x%02X\n", lt8713sx->main_crc_value);
324
325
if (main_crc_result == lt8713sx->main_crc_value)
326
dev_info(lt8713sx->dev, "Main Firmware Upgrade Success.\n");
327
else
328
dev_err(lt8713sx->dev, "Main Firmware Upgrade Failed.\n");
329
}
330
331
static void lt8713sx_bank_upgrade_result(struct lt8713sx *lt8713sx, u8 banknum)
332
{
333
u32 bank_crc_result;
334
335
regmap_read(lt8713sx->regmap, 0xe023, &bank_crc_result);
336
337
dev_dbg(lt8713sx->dev, "Bank %d CRC Result: 0x%02X\n", banknum, bank_crc_result);
338
339
if (bank_crc_result == lt8713sx->bank_crc_value[banknum])
340
dev_info(lt8713sx->dev, "Bank %d Firmware Upgrade Success.\n", banknum);
341
else
342
dev_err(lt8713sx->dev, "Bank %d Firmware Upgrade Failed.\n", banknum);
343
}
344
345
static void lt8713sx_bank_result_check(struct lt8713sx *lt8713sx)
346
{
347
int i;
348
u64 addr = 0x010000;
349
350
for (i = 0; i < lt8713sx->bank_num; i++) {
351
lt8713sx_load_bank_fw_to_sram(lt8713sx, addr);
352
lt8713sx_bank_upgrade_result(lt8713sx, i);
353
addr += 0x3000;
354
}
355
}
356
357
static int lt8713sx_firmware_upgrade(struct lt8713sx *lt8713sx)
358
{
359
int ret;
360
361
lt8713sx_config_parameters(lt8713sx);
362
363
lt8713sx_block_erase(lt8713sx);
364
365
if (lt8713sx->fw->size < SZ_64K) {
366
ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, SZ_64K);
367
if (ret < 0) {
368
dev_err(lt8713sx->dev, "Failed to write firmware data: %d\n", ret);
369
return ret;
370
}
371
} else {
372
ret = lt8713sx_write_data(lt8713sx, lt8713sx->fw_buffer, lt8713sx->fw->size);
373
if (ret < 0) {
374
dev_err(lt8713sx->dev, "Failed to write firmware data: %d\n", ret);
375
return ret;
376
}
377
}
378
dev_dbg(lt8713sx->dev, "Write Data done.\n");
379
380
return 0;
381
}
382
383
static int lt8713sx_firmware_update(struct lt8713sx *lt8713sx)
384
{
385
int ret = 0;
386
387
guard(mutex)(&lt8713sx->ocm_lock);
388
lt8713sx_i2c_enable(lt8713sx);
389
390
ret = lt8713sx_prepare_firmware_data(lt8713sx);
391
if (ret < 0) {
392
dev_err(lt8713sx->dev, "Failed to prepare firmware data: %d\n", ret);
393
goto error;
394
}
395
396
ret = lt8713sx_firmware_upgrade(lt8713sx);
397
if (ret < 0) {
398
dev_err(lt8713sx->dev, "Upgrade failure.\n");
399
goto error;
400
}
401
402
/* Validate CRC */
403
lt8713sx_load_main_fw_to_sram(lt8713sx);
404
lt8713sx_main_upgrade_result(lt8713sx);
405
lt8713sx_wrdi(lt8713sx);
406
lt8713sx_fifo_reset(lt8713sx);
407
lt8713sx_bank_result_check(lt8713sx);
408
lt8713sx_wrdi(lt8713sx);
409
410
error:
411
lt8713sx_i2c_disable(lt8713sx);
412
if (!ret)
413
lt8713sx_reset(lt8713sx);
414
415
kvfree(lt8713sx->fw_buffer);
416
lt8713sx->fw_buffer = NULL;
417
418
if (lt8713sx->fw) {
419
release_firmware(lt8713sx->fw);
420
lt8713sx->fw = NULL;
421
}
422
423
return ret;
424
}
425
426
static void lt8713sx_reset(struct lt8713sx *lt8713sx)
427
{
428
dev_dbg(lt8713sx->dev, "reset bridge.\n");
429
gpiod_set_value_cansleep(lt8713sx->reset_gpio, 1);
430
msleep(20);
431
432
gpiod_set_value_cansleep(lt8713sx->reset_gpio, 0);
433
msleep(20);
434
435
dev_dbg(lt8713sx->dev, "reset done.\n");
436
}
437
438
static int lt8713sx_regulator_enable(struct lt8713sx *lt8713sx)
439
{
440
int ret;
441
442
ret = devm_regulator_get_enable(lt8713sx->dev, "vdd");
443
if (ret < 0)
444
return dev_err_probe(lt8713sx->dev, ret, "failed to enable vdd regulator\n");
445
446
usleep_range(1000, 10000);
447
448
ret = devm_regulator_get_enable(lt8713sx->dev, "vcc");
449
if (ret < 0)
450
return dev_err_probe(lt8713sx->dev, ret, "failed to enable vcc regulator\n");
451
return 0;
452
}
453
454
static int lt8713sx_bridge_attach(struct drm_bridge *bridge,
455
struct drm_encoder *encoder,
456
enum drm_bridge_attach_flags flags)
457
{
458
struct lt8713sx *lt8713sx = container_of(bridge, struct lt8713sx, bridge);
459
460
return drm_bridge_attach(encoder,
461
lt8713sx->next_bridge,
462
bridge, flags);
463
}
464
465
static int lt8713sx_gpio_init(struct lt8713sx *lt8713sx)
466
{
467
struct device *dev = lt8713sx->dev;
468
469
lt8713sx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
470
if (IS_ERR(lt8713sx->reset_gpio))
471
return dev_err_probe(dev, PTR_ERR(lt8713sx->reset_gpio),
472
"failed to acquire reset gpio\n");
473
474
/* power enable gpio */
475
lt8713sx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
476
if (IS_ERR(lt8713sx->enable_gpio))
477
return dev_err_probe(dev, PTR_ERR(lt8713sx->enable_gpio),
478
"failed to acquire enable gpio\n");
479
return 0;
480
}
481
482
static ssize_t lt8713sx_firmware_store(struct device *dev,
483
struct device_attribute *attr,
484
const char *buf, size_t len)
485
{
486
struct lt8713sx *lt8713sx = dev_get_drvdata(dev);
487
int ret;
488
489
ret = lt8713sx_firmware_update(lt8713sx);
490
if (ret < 0)
491
return ret;
492
return len;
493
}
494
495
static DEVICE_ATTR_WO(lt8713sx_firmware);
496
497
static struct attribute *lt8713sx_attrs[] = {
498
&dev_attr_lt8713sx_firmware.attr,
499
NULL,
500
};
501
502
static const struct attribute_group lt8713sx_attr_group = {
503
.attrs = lt8713sx_attrs,
504
};
505
506
static const struct attribute_group *lt8713sx_attr_groups[] = {
507
&lt8713sx_attr_group,
508
NULL,
509
};
510
511
static const struct drm_bridge_funcs lt8713sx_bridge_funcs = {
512
.attach = lt8713sx_bridge_attach,
513
};
514
515
static int lt8713sx_probe(struct i2c_client *client)
516
{
517
struct lt8713sx *lt8713sx;
518
struct device *dev = &client->dev;
519
int ret;
520
521
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
522
return dev_err_probe(dev, -ENODEV, "device doesn't support I2C\n");
523
524
lt8713sx = devm_drm_bridge_alloc(dev, struct lt8713sx, bridge, &lt8713sx_bridge_funcs);
525
if (IS_ERR(lt8713sx))
526
return PTR_ERR(lt8713sx);
527
528
lt8713sx->dev = dev;
529
lt8713sx->client = client;
530
i2c_set_clientdata(client, lt8713sx);
531
532
ret = devm_mutex_init(lt8713sx->dev, &lt8713sx->ocm_lock);
533
if (ret)
534
return ret;
535
536
lt8713sx->regmap = devm_regmap_init_i2c(client, &lt8713sx_regmap_config);
537
if (IS_ERR(lt8713sx->regmap))
538
return dev_err_probe(dev, PTR_ERR(lt8713sx->regmap), "regmap i2c init failed\n");
539
540
ret = drm_of_find_panel_or_bridge(lt8713sx->dev->of_node, 1, -1, NULL,
541
&lt8713sx->next_bridge);
542
if (ret < 0)
543
return ret;
544
545
ret = lt8713sx_gpio_init(lt8713sx);
546
if (ret < 0)
547
return ret;
548
549
ret = lt8713sx_regulator_enable(lt8713sx);
550
if (ret)
551
return ret;
552
553
lt8713sx_reset(lt8713sx);
554
555
lt8713sx->bridge.funcs = &lt8713sx_bridge_funcs;
556
lt8713sx->bridge.of_node = dev->of_node;
557
lt8713sx->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
558
drm_bridge_add(&lt8713sx->bridge);
559
560
crc8_populate_msb(lt8713sx_crc_table, 0x31);
561
562
return 0;
563
}
564
565
static void lt8713sx_remove(struct i2c_client *client)
566
{
567
struct lt8713sx *lt8713sx = i2c_get_clientdata(client);
568
569
drm_bridge_remove(&lt8713sx->bridge);
570
}
571
572
static struct i2c_device_id lt8713sx_id[] = {
573
{ "lontium,lt8713sx", 0 },
574
{ /* sentinel */ }
575
};
576
577
static const struct of_device_id lt8713sx_match_table[] = {
578
{ .compatible = "lontium,lt8713sx" },
579
{ /* sentinel */ }
580
};
581
MODULE_DEVICE_TABLE(of, lt8713sx_match_table);
582
583
static struct i2c_driver lt8713sx_driver = {
584
.driver = {
585
.name = "lt8713sx",
586
.of_match_table = lt8713sx_match_table,
587
.dev_groups = lt8713sx_attr_groups,
588
},
589
.probe = lt8713sx_probe,
590
.remove = lt8713sx_remove,
591
.id_table = lt8713sx_id,
592
};
593
594
module_i2c_driver(lt8713sx_driver);
595
MODULE_LICENSE("GPL");
596
MODULE_DESCRIPTION("lt8713sx drm bridge driver");
597
MODULE_AUTHOR("Vishnu Saini <[email protected]>");
598
MODULE_FIRMWARE(FW_FILE);
599
600