xref: /dflybsd-src/sys/dev/drm/i915/dvo_sil164.c (revision bf0175970ba1c394f8039834a26ca6d163b23d0e)
1ba55f2f5SFrançois Tigeot /**************************************************************************
2ba55f2f5SFrançois Tigeot 
3ba55f2f5SFrançois Tigeot Copyright © 2006 Dave Airlie
4ba55f2f5SFrançois Tigeot 
5ba55f2f5SFrançois Tigeot All Rights Reserved.
6ba55f2f5SFrançois Tigeot 
7ba55f2f5SFrançois Tigeot Permission is hereby granted, free of charge, to any person obtaining a
8ba55f2f5SFrançois Tigeot copy of this software and associated documentation files (the
9ba55f2f5SFrançois Tigeot "Software"), to deal in the Software without restriction, including
10ba55f2f5SFrançois Tigeot without limitation the rights to use, copy, modify, merge, publish,
11ba55f2f5SFrançois Tigeot distribute, sub license, and/or sell copies of the Software, and to
12ba55f2f5SFrançois Tigeot permit persons to whom the Software is furnished to do so, subject to
13ba55f2f5SFrançois Tigeot the following conditions:
14ba55f2f5SFrançois Tigeot 
15ba55f2f5SFrançois Tigeot The above copyright notice and this permission notice (including the
16ba55f2f5SFrançois Tigeot next paragraph) shall be included in all copies or substantial portions
17ba55f2f5SFrançois Tigeot of the Software.
18ba55f2f5SFrançois Tigeot 
19ba55f2f5SFrançois Tigeot THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20ba55f2f5SFrançois Tigeot OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21ba55f2f5SFrançois Tigeot MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22ba55f2f5SFrançois Tigeot IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
23ba55f2f5SFrançois Tigeot ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24ba55f2f5SFrançois Tigeot TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25ba55f2f5SFrançois Tigeot SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26ba55f2f5SFrançois Tigeot 
27ba55f2f5SFrançois Tigeot **************************************************************************/
28ba55f2f5SFrançois Tigeot 
29ba55f2f5SFrançois Tigeot #include "dvo.h"
30ba55f2f5SFrançois Tigeot 
31ba55f2f5SFrançois Tigeot #define SIL164_VID 0x0001
32ba55f2f5SFrançois Tigeot #define SIL164_DID 0x0006
33ba55f2f5SFrançois Tigeot 
34ba55f2f5SFrançois Tigeot #define SIL164_VID_LO 0x00
35ba55f2f5SFrançois Tigeot #define SIL164_VID_HI 0x01
36ba55f2f5SFrançois Tigeot #define SIL164_DID_LO 0x02
37ba55f2f5SFrançois Tigeot #define SIL164_DID_HI 0x03
38ba55f2f5SFrançois Tigeot #define SIL164_REV    0x04
39ba55f2f5SFrançois Tigeot #define SIL164_RSVD   0x05
40ba55f2f5SFrançois Tigeot #define SIL164_FREQ_LO 0x06
41ba55f2f5SFrançois Tigeot #define SIL164_FREQ_HI 0x07
42ba55f2f5SFrançois Tigeot 
43ba55f2f5SFrançois Tigeot #define SIL164_REG8 0x08
44ba55f2f5SFrançois Tigeot #define SIL164_8_VEN (1<<5)
45ba55f2f5SFrançois Tigeot #define SIL164_8_HEN (1<<4)
46ba55f2f5SFrançois Tigeot #define SIL164_8_DSEL (1<<3)
47ba55f2f5SFrançois Tigeot #define SIL164_8_BSEL (1<<2)
48ba55f2f5SFrançois Tigeot #define SIL164_8_EDGE (1<<1)
49ba55f2f5SFrançois Tigeot #define SIL164_8_PD   (1<<0)
50ba55f2f5SFrançois Tigeot 
51ba55f2f5SFrançois Tigeot #define SIL164_REG9 0x09
52ba55f2f5SFrançois Tigeot #define SIL164_9_VLOW (1<<7)
53ba55f2f5SFrançois Tigeot #define SIL164_9_MSEL_MASK (0x7<<4)
54ba55f2f5SFrançois Tigeot #define SIL164_9_TSEL (1<<3)
55ba55f2f5SFrançois Tigeot #define SIL164_9_RSEN (1<<2)
56ba55f2f5SFrançois Tigeot #define SIL164_9_HTPLG (1<<1)
57ba55f2f5SFrançois Tigeot #define SIL164_9_MDI (1<<0)
58ba55f2f5SFrançois Tigeot 
59ba55f2f5SFrançois Tigeot #define SIL164_REGC 0x0c
60ba55f2f5SFrançois Tigeot 
61ba55f2f5SFrançois Tigeot struct sil164_priv {
62ba55f2f5SFrançois Tigeot 	//I2CDevRec d;
63ba55f2f5SFrançois Tigeot 	bool quiet;
64ba55f2f5SFrançois Tigeot };
65ba55f2f5SFrançois Tigeot 
66ba55f2f5SFrançois Tigeot #define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
67ba55f2f5SFrançois Tigeot 
sil164_readb(struct intel_dvo_device * dvo,int addr,uint8_t * ch)68ba55f2f5SFrançois Tigeot static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
69ba55f2f5SFrançois Tigeot {
70ba55f2f5SFrançois Tigeot 	struct sil164_priv *sil = dvo->dev_priv;
71ba55f2f5SFrançois Tigeot 	struct i2c_adapter *adapter = dvo->i2c_bus;
72ba55f2f5SFrançois Tigeot 	u8 out_buf[2];
73ba55f2f5SFrançois Tigeot 	u8 in_buf[2];
74ba55f2f5SFrançois Tigeot 
75ba55f2f5SFrançois Tigeot 	struct i2c_msg msgs[] = {
76ba55f2f5SFrançois Tigeot 		{
779f4ca867SFrançois Tigeot 			.addr = dvo->slave_addr,
78ba55f2f5SFrançois Tigeot 			.flags = 0,
79ba55f2f5SFrançois Tigeot 			.len = 1,
80ba55f2f5SFrançois Tigeot 			.buf = out_buf,
81ba55f2f5SFrançois Tigeot 		},
82ba55f2f5SFrançois Tigeot 		{
839f4ca867SFrançois Tigeot 			.addr = dvo->slave_addr,
84ba55f2f5SFrançois Tigeot 			.flags = I2C_M_RD,
85ba55f2f5SFrançois Tigeot 			.len = 1,
86ba55f2f5SFrançois Tigeot 			.buf = in_buf,
87ba55f2f5SFrançois Tigeot 		}
88ba55f2f5SFrançois Tigeot 	};
89ba55f2f5SFrançois Tigeot 
90ba55f2f5SFrançois Tigeot 	out_buf[0] = addr;
91ba55f2f5SFrançois Tigeot 	out_buf[1] = 0;
92ba55f2f5SFrançois Tigeot 
939f4ca867SFrançois Tigeot 	if (i2c_transfer(adapter, msgs, 2) == 2) {
94ba55f2f5SFrançois Tigeot 		*ch = in_buf[0];
95ba55f2f5SFrançois Tigeot 		return true;
96ba55f2f5SFrançois Tigeot 	}
97ba55f2f5SFrançois Tigeot 
98ba55f2f5SFrançois Tigeot 	if (!sil->quiet) {
99ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
1009f4ca867SFrançois Tigeot 			  addr, adapter->name, dvo->slave_addr);
101ba55f2f5SFrançois Tigeot 	}
102ba55f2f5SFrançois Tigeot 	return false;
103ba55f2f5SFrançois Tigeot }
104ba55f2f5SFrançois Tigeot 
sil164_writeb(struct intel_dvo_device * dvo,int addr,uint8_t ch)105ba55f2f5SFrançois Tigeot static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
106ba55f2f5SFrançois Tigeot {
107ba55f2f5SFrançois Tigeot 	struct sil164_priv *sil = dvo->dev_priv;
108ba55f2f5SFrançois Tigeot 	struct i2c_adapter *adapter = dvo->i2c_bus;
109ba55f2f5SFrançois Tigeot 	uint8_t out_buf[2];
110ba55f2f5SFrançois Tigeot 	struct i2c_msg msg = {
1119f4ca867SFrançois Tigeot 		.addr = dvo->slave_addr,
112ba55f2f5SFrançois Tigeot 		.flags = 0,
113ba55f2f5SFrançois Tigeot 		.len = 2,
114ba55f2f5SFrançois Tigeot 		.buf = out_buf,
115ba55f2f5SFrançois Tigeot 	};
116ba55f2f5SFrançois Tigeot 
117ba55f2f5SFrançois Tigeot 	out_buf[0] = addr;
118ba55f2f5SFrançois Tigeot 	out_buf[1] = ch;
119ba55f2f5SFrançois Tigeot 
1209f4ca867SFrançois Tigeot 	if (i2c_transfer(adapter, &msg, 1) == 1)
121ba55f2f5SFrançois Tigeot 		return true;
122ba55f2f5SFrançois Tigeot 
123ba55f2f5SFrançois Tigeot 	if (!sil->quiet) {
124ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
1259f4ca867SFrançois Tigeot 			  addr, adapter->name, dvo->slave_addr);
126ba55f2f5SFrançois Tigeot 	}
127ba55f2f5SFrançois Tigeot 
128ba55f2f5SFrançois Tigeot 	return false;
129ba55f2f5SFrançois Tigeot }
130ba55f2f5SFrançois Tigeot 
131ba55f2f5SFrançois Tigeot /* Silicon Image 164 driver for chip on i2c bus */
sil164_init(struct intel_dvo_device * dvo,struct i2c_adapter * adapter)132ba55f2f5SFrançois Tigeot static bool sil164_init(struct intel_dvo_device *dvo,
133ba55f2f5SFrançois Tigeot 			struct i2c_adapter *adapter)
134ba55f2f5SFrançois Tigeot {
135ba55f2f5SFrançois Tigeot 	/* this will detect the SIL164 chip on the specified i2c bus */
136ba55f2f5SFrançois Tigeot 	struct sil164_priv *sil;
137ba55f2f5SFrançois Tigeot 	unsigned char ch;
138ba55f2f5SFrançois Tigeot 
139ba55f2f5SFrançois Tigeot 	sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
140ba55f2f5SFrançois Tigeot 	if (sil == NULL)
141ba55f2f5SFrançois Tigeot 		return false;
142ba55f2f5SFrançois Tigeot 
143ba55f2f5SFrançois Tigeot 	dvo->i2c_bus = adapter;
144ba55f2f5SFrançois Tigeot 	dvo->dev_priv = sil;
145ba55f2f5SFrançois Tigeot 	sil->quiet = true;
146ba55f2f5SFrançois Tigeot 
147ba55f2f5SFrançois Tigeot 	if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
148ba55f2f5SFrançois Tigeot 		goto out;
149ba55f2f5SFrançois Tigeot 
150ba55f2f5SFrançois Tigeot 	if (ch != (SIL164_VID & 0xff)) {
151ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
1529f4ca867SFrançois Tigeot 			  ch, adapter->name, dvo->slave_addr);
153ba55f2f5SFrançois Tigeot 		goto out;
154ba55f2f5SFrançois Tigeot 	}
155ba55f2f5SFrançois Tigeot 
156ba55f2f5SFrançois Tigeot 	if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
157ba55f2f5SFrançois Tigeot 		goto out;
158ba55f2f5SFrançois Tigeot 
159ba55f2f5SFrançois Tigeot 	if (ch != (SIL164_DID & 0xff)) {
160ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
1619f4ca867SFrançois Tigeot 			  ch, adapter->name, dvo->slave_addr);
162ba55f2f5SFrançois Tigeot 		goto out;
163ba55f2f5SFrançois Tigeot 	}
164ba55f2f5SFrançois Tigeot 	sil->quiet = false;
165ba55f2f5SFrançois Tigeot 
166ba55f2f5SFrançois Tigeot 	DRM_DEBUG_KMS("init sil164 dvo controller successfully!\n");
167ba55f2f5SFrançois Tigeot 	return true;
168ba55f2f5SFrançois Tigeot 
169ba55f2f5SFrançois Tigeot out:
170ba55f2f5SFrançois Tigeot 	kfree(sil);
171ba55f2f5SFrançois Tigeot 	return false;
172ba55f2f5SFrançois Tigeot }
173ba55f2f5SFrançois Tigeot 
sil164_detect(struct intel_dvo_device * dvo)174ba55f2f5SFrançois Tigeot static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
175ba55f2f5SFrançois Tigeot {
176ba55f2f5SFrançois Tigeot 	uint8_t reg9;
177ba55f2f5SFrançois Tigeot 
178ba55f2f5SFrançois Tigeot 	sil164_readb(dvo, SIL164_REG9, &reg9);
179ba55f2f5SFrançois Tigeot 
180ba55f2f5SFrançois Tigeot 	if (reg9 & SIL164_9_HTPLG)
181ba55f2f5SFrançois Tigeot 		return connector_status_connected;
182ba55f2f5SFrançois Tigeot 	else
183ba55f2f5SFrançois Tigeot 		return connector_status_disconnected;
184ba55f2f5SFrançois Tigeot }
185ba55f2f5SFrançois Tigeot 
sil164_mode_valid(struct intel_dvo_device * dvo,struct drm_display_mode * mode)186ba55f2f5SFrançois Tigeot static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
187ba55f2f5SFrançois Tigeot 					      struct drm_display_mode *mode)
188ba55f2f5SFrançois Tigeot {
189ba55f2f5SFrançois Tigeot 	return MODE_OK;
190ba55f2f5SFrançois Tigeot }
191ba55f2f5SFrançois Tigeot 
sil164_mode_set(struct intel_dvo_device * dvo,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)192ba55f2f5SFrançois Tigeot static void sil164_mode_set(struct intel_dvo_device *dvo,
193352ff8bdSFrançois Tigeot 			    const struct drm_display_mode *mode,
194352ff8bdSFrançois Tigeot 			    const struct drm_display_mode *adjusted_mode)
195ba55f2f5SFrançois Tigeot {
196ba55f2f5SFrançois Tigeot 	/* As long as the basics are set up, since we don't have clock
197ba55f2f5SFrançois Tigeot 	 * dependencies in the mode setup, we can just leave the
198ba55f2f5SFrançois Tigeot 	 * registers alone and everything will work fine.
199ba55f2f5SFrançois Tigeot 	 */
200ba55f2f5SFrançois Tigeot 	/* recommended programming sequence from doc */
201ba55f2f5SFrançois Tigeot 	/*sil164_writeb(sil, 0x08, 0x30);
202ba55f2f5SFrançois Tigeot 	  sil164_writeb(sil, 0x09, 0x00);
203ba55f2f5SFrançois Tigeot 	  sil164_writeb(sil, 0x0a, 0x90);
204ba55f2f5SFrançois Tigeot 	  sil164_writeb(sil, 0x0c, 0x89);
205ba55f2f5SFrançois Tigeot 	  sil164_writeb(sil, 0x08, 0x31);*/
206ba55f2f5SFrançois Tigeot 	/* don't do much */
207ba55f2f5SFrançois Tigeot 	return;
208ba55f2f5SFrançois Tigeot }
209ba55f2f5SFrançois Tigeot 
210ba55f2f5SFrançois Tigeot /* set the SIL164 power state */
sil164_dpms(struct intel_dvo_device * dvo,bool enable)211ba55f2f5SFrançois Tigeot static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
212ba55f2f5SFrançois Tigeot {
213ba55f2f5SFrançois Tigeot 	int ret;
214ba55f2f5SFrançois Tigeot 	unsigned char ch;
215ba55f2f5SFrançois Tigeot 
216ba55f2f5SFrançois Tigeot 	ret = sil164_readb(dvo, SIL164_REG8, &ch);
217ba55f2f5SFrançois Tigeot 	if (ret == false)
218ba55f2f5SFrançois Tigeot 		return;
219ba55f2f5SFrançois Tigeot 
220ba55f2f5SFrançois Tigeot 	if (enable)
221ba55f2f5SFrançois Tigeot 		ch |= SIL164_8_PD;
222ba55f2f5SFrançois Tigeot 	else
223ba55f2f5SFrançois Tigeot 		ch &= ~SIL164_8_PD;
224ba55f2f5SFrançois Tigeot 
225ba55f2f5SFrançois Tigeot 	sil164_writeb(dvo, SIL164_REG8, ch);
226ba55f2f5SFrançois Tigeot 	return;
227ba55f2f5SFrançois Tigeot }
228ba55f2f5SFrançois Tigeot 
sil164_get_hw_state(struct intel_dvo_device * dvo)229ba55f2f5SFrançois Tigeot static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
230ba55f2f5SFrançois Tigeot {
231ba55f2f5SFrançois Tigeot 	int ret;
232ba55f2f5SFrançois Tigeot 	unsigned char ch;
233ba55f2f5SFrançois Tigeot 
234ba55f2f5SFrançois Tigeot 	ret = sil164_readb(dvo, SIL164_REG8, &ch);
235ba55f2f5SFrançois Tigeot 	if (ret == false)
236ba55f2f5SFrançois Tigeot 		return false;
237ba55f2f5SFrançois Tigeot 
238ba55f2f5SFrançois Tigeot 	if (ch & SIL164_8_PD)
239ba55f2f5SFrançois Tigeot 		return true;
240ba55f2f5SFrançois Tigeot 	else
241ba55f2f5SFrançois Tigeot 		return false;
242ba55f2f5SFrançois Tigeot }
243ba55f2f5SFrançois Tigeot 
sil164_dump_regs(struct intel_dvo_device * dvo)244ba55f2f5SFrançois Tigeot static void sil164_dump_regs(struct intel_dvo_device *dvo)
245ba55f2f5SFrançois Tigeot {
246ba55f2f5SFrançois Tigeot 	uint8_t val;
247ba55f2f5SFrançois Tigeot 
248ba55f2f5SFrançois Tigeot 	sil164_readb(dvo, SIL164_FREQ_LO, &val);
249ba55f2f5SFrançois Tigeot 	DRM_DEBUG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
250ba55f2f5SFrançois Tigeot 	sil164_readb(dvo, SIL164_FREQ_HI, &val);
251ba55f2f5SFrançois Tigeot 	DRM_DEBUG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
252ba55f2f5SFrançois Tigeot 	sil164_readb(dvo, SIL164_REG8, &val);
253ba55f2f5SFrançois Tigeot 	DRM_DEBUG_KMS("SIL164_REG8: 0x%02x\n", val);
254ba55f2f5SFrançois Tigeot 	sil164_readb(dvo, SIL164_REG9, &val);
255ba55f2f5SFrançois Tigeot 	DRM_DEBUG_KMS("SIL164_REG9: 0x%02x\n", val);
256ba55f2f5SFrançois Tigeot 	sil164_readb(dvo, SIL164_REGC, &val);
257ba55f2f5SFrançois Tigeot 	DRM_DEBUG_KMS("SIL164_REGC: 0x%02x\n", val);
258ba55f2f5SFrançois Tigeot }
259ba55f2f5SFrançois Tigeot 
sil164_destroy(struct intel_dvo_device * dvo)260ba55f2f5SFrançois Tigeot static void sil164_destroy(struct intel_dvo_device *dvo)
261ba55f2f5SFrançois Tigeot {
262ba55f2f5SFrançois Tigeot 	struct sil164_priv *sil = dvo->dev_priv;
263ba55f2f5SFrançois Tigeot 
264ba55f2f5SFrançois Tigeot 	if (sil) {
265ba55f2f5SFrançois Tigeot 		kfree(sil);
266ba55f2f5SFrançois Tigeot 		dvo->dev_priv = NULL;
267ba55f2f5SFrançois Tigeot 	}
268ba55f2f5SFrançois Tigeot }
269ba55f2f5SFrançois Tigeot 
270*aee94f86SFrançois Tigeot const struct intel_dvo_dev_ops sil164_ops = {
271ba55f2f5SFrançois Tigeot 	.init = sil164_init,
272ba55f2f5SFrançois Tigeot 	.detect = sil164_detect,
273ba55f2f5SFrançois Tigeot 	.mode_valid = sil164_mode_valid,
274ba55f2f5SFrançois Tigeot 	.mode_set = sil164_mode_set,
275ba55f2f5SFrançois Tigeot 	.dpms = sil164_dpms,
276ba55f2f5SFrançois Tigeot 	.get_hw_state = sil164_get_hw_state,
277ba55f2f5SFrançois Tigeot 	.dump_regs = sil164_dump_regs,
278ba55f2f5SFrançois Tigeot 	.destroy = sil164_destroy,
279ba55f2f5SFrançois Tigeot };
280