1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <device/device.h>
5 #include <device/i2c_bus.h>
12 * \brief This function selects one of 7 EDID-tables inside PTN3460
13 * which should be emulated on display port and turn emulation ON
14 * @param *dev Pointer to the relevant I2C controller
15 * @param edid_num Number of EDID to emulate (0..6)
16 * @return PTN_SUCCESS or error code
18 static int ptn_select_edid(struct device
*dev
, uint8_t edid_num
)
23 if (edid_num
> PTN_MAX_EDID_NUM
)
24 return PTN_INVALID_EDID
;
25 val
= (edid_num
<< 1) | PTN_ENABLE_EMULATION
;
26 status
= i2c_dev_writeb_at(dev
, PTN_CONFIG_OFF
+ 4, val
);
27 return status
? (PTN_BUS_ERROR
| status
) : PTN_SUCCESS
;
31 * \brief This function writes one EDID data structure to PTN3460
32 * @param *dev Pointer to the relevant I2C controller
33 * @param edid_num Number of EDID that must be written (0..6)
34 * @param *data Pointer to a buffer where data to write is stored in
35 * @return PTN_SUCCESS on success or error code
37 static int ptn3460_write_edid(struct device
*dev
, u8 edid_num
, u8
*data
)
42 if (edid_num
> PTN_MAX_EDID_NUM
)
43 return PTN_INVALID_EDID
;
45 /* First enable access to the desired EDID table */
46 status
= i2c_dev_writeb_at(dev
, PTN_CONFIG_OFF
+ 5, edid_num
);
48 return (PTN_BUS_ERROR
| status
);
50 /* Now we can simply write EDID data to ptn3460 */
51 for (i
= 0; i
< PTN_EDID_LEN
; i
++) {
52 status
= i2c_dev_writeb_at(dev
, PTN_EDID_OFF
+ i
, data
[i
]);
54 return (PTN_BUS_ERROR
| status
);
60 * \brief This function sets up the DP2LVDS-converter to be used with the
61 * appropriate EDID data
62 * @param *dev Pointer to the I2C controller where PTN3460 is attached
64 static void ptn3460_init(struct device
*dev
)
66 struct ptn_3460_config cfg
;
67 uint8_t edid_data
[PTN_EDID_LEN
], edid_tab
, *ptr
= (uint8_t *)&cfg
;
70 /* Guard against re-initialization of the device */
71 static bool init_done
= false;
74 printk(BIOS_DEBUG
, "Skipping PTN3460 init as it's already initialized\n");
78 /* Mainboard provides EDID data. */
79 if (mainboard_ptn3460_get_edid(edid_data
) != CB_SUCCESS
) {
80 printk(BIOS_ERR
, "PTN3460 error: Unable to get EDID data from mainboard.\n");
84 /* Mainboard decides which EDID table has to be used. */
85 edid_tab
= mainboard_ptn3460_select_edid_table();
86 if (edid_tab
> PTN_MAX_EDID_NUM
) {
87 printk(BIOS_ERR
, "PTN3460 error: invalid EDID table (%d) selected.\n",
91 /* Write EDID data into PTN. */
92 val
= ptn3460_write_edid(dev
, edid_tab
, edid_data
);
93 if (val
!= PTN_SUCCESS
) {
94 printk(BIOS_ERR
, "PTN3460 error: writing EDID data into device failed.\n");
97 /* Activate the selected EDID block. */
98 ptn_select_edid(dev
, edid_tab
);
99 /* Read out PTN configuration data. */
100 for (i
= 0; i
< sizeof(struct ptn_3460_config
); i
++) {
101 val
= i2c_dev_readb_at(dev
, PTN_CONFIG_OFF
+ i
);
104 "PTN3460 error: Unable to read config data from device.\n");
107 *ptr
++ = (uint8_t)val
; /* fill config structure via ptr */
109 /* Mainboard can modify the configuration data.
110 Write back configuration data to PTN3460 if modified by mainboard */
111 if (mainboard_ptn3460_config(&cfg
) == CB_SUCCESS
) {
112 ptr
= (uint8_t *)&cfg
;
113 for (i
= 0; i
< sizeof(struct ptn_3460_config
); i
++) {
114 val
= i2c_dev_writeb_at(dev
, PTN_CONFIG_OFF
+ i
, *ptr
++);
117 "PTN3460 error: Unable to write config data.\n");
126 __weak
enum cb_err
mainboard_ptn3460_get_edid(uint8_t edid_data
[PTN_EDID_LEN
])
130 __weak
uint8_t mainboard_ptn3460_select_edid_table(void)
134 __weak
enum cb_err
mainboard_ptn3460_config(struct ptn_3460_config
*cfg_ptr
)
139 static struct device_operations ptn3460_ops
= {
140 .read_resources
= noop_read_resources
,
141 .set_resources
= noop_set_resources
,
142 .init
= ptn3460_init
,
145 static void ptn3460_enable(struct device
*dev
)
147 dev
->ops
= &ptn3460_ops
;
150 struct chip_operations drivers_i2c_ptn3460_ops
= {
152 .enable_dev
= ptn3460_enable
155 #if CONFIG(PTN3460_EARLY_INIT)
158 * \brief This function provides a callback for the boot state machine to initialize the
159 * PTN3460 DP-to-LVDS bridge before graphics initialization in order for the bootsplash
161 * @param *unused Unused argument for the callback.
164 static void ptn3460_early_init(void *unused
)
166 struct device
*ptn_dev
;
168 printk(BIOS_DEBUG
, "Attempting PTN3460 early init.\n");
169 ptn_dev
= dev_find_slot_on_smbus(0, CONFIG_PTN3460_EARLY_ADDR
);
171 printk(BIOS_ERR
, "Failed to find the PTN3460 device!\n");
174 /* Initialize the I2C controller before it is used. */
175 if (ptn_dev
->upstream
&& ptn_dev
->upstream
->dev
->ops
&& ptn_dev
->upstream
->dev
->ops
->init
)
176 ptn_dev
->upstream
->dev
->ops
->init(ptn_dev
->upstream
->dev
);
177 ptn3460_init(ptn_dev
);
180 BOOT_STATE_INIT_ENTRY(BS_DEV_INIT
, BS_ON_ENTRY
, ptn3460_early_init
, NULL
);
182 #endif /* CONFIG(PTN3460_EARLY_INIT) */