Home | History | Annotate | Line # | Download | only in display
      1  1.1  riastrad /*	$NetBSD: dvo_ch7xxx.c,v 1.2 2021/12/18 23:45:29 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad /**************************************************************************
      4  1.1  riastrad 
      5  1.1  riastrad Copyright  2006 Dave Airlie
      6  1.1  riastrad 
      7  1.1  riastrad All Rights Reserved.
      8  1.1  riastrad 
      9  1.1  riastrad Permission is hereby granted, free of charge, to any person obtaining a
     10  1.1  riastrad copy of this software and associated documentation files (the
     11  1.1  riastrad "Software"), to deal in the Software without restriction, including
     12  1.1  riastrad without limitation the rights to use, copy, modify, merge, publish,
     13  1.1  riastrad distribute, sub license, and/or sell copies of the Software, and to
     14  1.1  riastrad permit persons to whom the Software is furnished to do so, subject to
     15  1.1  riastrad the following conditions:
     16  1.1  riastrad 
     17  1.1  riastrad The above copyright notice and this permission notice (including the
     18  1.1  riastrad next paragraph) shall be included in all copies or substantial portions
     19  1.1  riastrad of the Software.
     20  1.1  riastrad 
     21  1.1  riastrad THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     22  1.1  riastrad OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     23  1.1  riastrad MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     24  1.1  riastrad IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     25  1.1  riastrad ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     26  1.1  riastrad TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     27  1.1  riastrad SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     28  1.1  riastrad 
     29  1.1  riastrad **************************************************************************/
     30  1.1  riastrad 
     31  1.1  riastrad #include <sys/cdefs.h>
     32  1.1  riastrad __KERNEL_RCSID(0, "$NetBSD: dvo_ch7xxx.c,v 1.2 2021/12/18 23:45:29 riastradh Exp $");
     33  1.1  riastrad 
     34  1.1  riastrad #include "intel_display_types.h"
     35  1.1  riastrad #include "intel_dvo_dev.h"
     36  1.1  riastrad 
     37  1.1  riastrad #define CH7xxx_REG_VID		0x4a
     38  1.1  riastrad #define CH7xxx_REG_DID		0x4b
     39  1.1  riastrad 
     40  1.1  riastrad #define CH7011_VID		0x83 /* 7010 as well */
     41  1.1  riastrad #define CH7010B_VID		0x05
     42  1.1  riastrad #define CH7009A_VID		0x84
     43  1.1  riastrad #define CH7009B_VID		0x85
     44  1.1  riastrad #define CH7301_VID		0x95
     45  1.1  riastrad 
     46  1.1  riastrad #define CH7xxx_VID		0x84
     47  1.1  riastrad #define CH7xxx_DID		0x17
     48  1.1  riastrad #define CH7010_DID		0x16
     49  1.1  riastrad 
     50  1.1  riastrad #define CH7xxx_NUM_REGS		0x4c
     51  1.1  riastrad 
     52  1.1  riastrad #define CH7xxx_CM		0x1c
     53  1.1  riastrad #define CH7xxx_CM_XCM		(1<<0)
     54  1.1  riastrad #define CH7xxx_CM_MCP		(1<<2)
     55  1.1  riastrad #define CH7xxx_INPUT_CLOCK	0x1d
     56  1.1  riastrad #define CH7xxx_GPIO		0x1e
     57  1.1  riastrad #define CH7xxx_GPIO_HPIR	(1<<3)
     58  1.1  riastrad #define CH7xxx_IDF		0x1f
     59  1.1  riastrad 
     60  1.1  riastrad #define CH7xxx_IDF_HSP		(1<<3)
     61  1.1  riastrad #define CH7xxx_IDF_VSP		(1<<4)
     62  1.1  riastrad 
     63  1.1  riastrad #define CH7xxx_CONNECTION_DETECT 0x20
     64  1.1  riastrad #define CH7xxx_CDET_DVI		(1<<5)
     65  1.1  riastrad 
     66  1.1  riastrad #define CH7301_DAC_CNTL		0x21
     67  1.1  riastrad #define CH7301_HOTPLUG		0x23
     68  1.1  riastrad #define CH7xxx_TCTL		0x31
     69  1.1  riastrad #define CH7xxx_TVCO		0x32
     70  1.1  riastrad #define CH7xxx_TPCP		0x33
     71  1.1  riastrad #define CH7xxx_TPD		0x34
     72  1.1  riastrad #define CH7xxx_TPVT		0x35
     73  1.1  riastrad #define CH7xxx_TLPF		0x36
     74  1.1  riastrad #define CH7xxx_TCT		0x37
     75  1.1  riastrad #define CH7301_TEST_PATTERN	0x48
     76  1.1  riastrad 
     77  1.1  riastrad #define CH7xxx_PM		0x49
     78  1.1  riastrad #define CH7xxx_PM_FPD		(1<<0)
     79  1.1  riastrad #define CH7301_PM_DACPD0	(1<<1)
     80  1.1  riastrad #define CH7301_PM_DACPD1	(1<<2)
     81  1.1  riastrad #define CH7301_PM_DACPD2	(1<<3)
     82  1.1  riastrad #define CH7xxx_PM_DVIL		(1<<6)
     83  1.1  riastrad #define CH7xxx_PM_DVIP		(1<<7)
     84  1.1  riastrad 
     85  1.1  riastrad #define CH7301_SYNC_POLARITY	0x56
     86  1.1  riastrad #define CH7301_SYNC_RGB_YUV	(1<<0)
     87  1.1  riastrad #define CH7301_SYNC_POL_DVI	(1<<5)
     88  1.1  riastrad 
     89  1.1  riastrad /** @file
     90  1.1  riastrad  * driver for the Chrontel 7xxx DVI chip over DVO.
     91  1.1  riastrad  */
     92  1.1  riastrad 
     93  1.1  riastrad static struct ch7xxx_id_struct {
     94  1.1  riastrad 	u8 vid;
     95  1.2  riastrad 	const char *name;
     96  1.1  riastrad } ch7xxx_ids[] = {
     97  1.1  riastrad 	{ CH7011_VID, "CH7011" },
     98  1.1  riastrad 	{ CH7010B_VID, "CH7010B" },
     99  1.1  riastrad 	{ CH7009A_VID, "CH7009A" },
    100  1.1  riastrad 	{ CH7009B_VID, "CH7009B" },
    101  1.1  riastrad 	{ CH7301_VID, "CH7301" },
    102  1.1  riastrad };
    103  1.1  riastrad 
    104  1.1  riastrad static struct ch7xxx_did_struct {
    105  1.1  riastrad 	u8 did;
    106  1.2  riastrad 	const char *name;
    107  1.1  riastrad } ch7xxx_dids[] = {
    108  1.1  riastrad 	{ CH7xxx_DID, "CH7XXX" },
    109  1.1  riastrad 	{ CH7010_DID, "CH7010B" },
    110  1.1  riastrad };
    111  1.1  riastrad 
    112  1.1  riastrad struct ch7xxx_priv {
    113  1.1  riastrad 	bool quiet;
    114  1.1  riastrad };
    115  1.1  riastrad 
    116  1.2  riastrad static const char *ch7xxx_get_id(u8 vid)
    117  1.1  riastrad {
    118  1.1  riastrad 	int i;
    119  1.1  riastrad 
    120  1.1  riastrad 	for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
    121  1.1  riastrad 		if (ch7xxx_ids[i].vid == vid)
    122  1.1  riastrad 			return ch7xxx_ids[i].name;
    123  1.1  riastrad 	}
    124  1.1  riastrad 
    125  1.1  riastrad 	return NULL;
    126  1.1  riastrad }
    127  1.1  riastrad 
    128  1.2  riastrad static const char *ch7xxx_get_did(u8 did)
    129  1.1  riastrad {
    130  1.1  riastrad 	int i;
    131  1.1  riastrad 
    132  1.1  riastrad 	for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) {
    133  1.1  riastrad 		if (ch7xxx_dids[i].did == did)
    134  1.1  riastrad 			return ch7xxx_dids[i].name;
    135  1.1  riastrad 	}
    136  1.1  riastrad 
    137  1.1  riastrad 	return NULL;
    138  1.1  riastrad }
    139  1.1  riastrad 
    140  1.1  riastrad /** Reads an 8 bit register */
    141  1.1  riastrad static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
    142  1.1  riastrad {
    143  1.1  riastrad 	struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
    144  1.1  riastrad 	struct i2c_adapter *adapter = dvo->i2c_bus;
    145  1.1  riastrad 	u8 out_buf[2];
    146  1.1  riastrad 	u8 in_buf[2];
    147  1.1  riastrad 
    148  1.1  riastrad 	struct i2c_msg msgs[] = {
    149  1.1  riastrad 		{
    150  1.1  riastrad 			.addr = dvo->slave_addr,
    151  1.1  riastrad 			.flags = 0,
    152  1.1  riastrad 			.len = 1,
    153  1.1  riastrad 			.buf = out_buf,
    154  1.1  riastrad 		},
    155  1.1  riastrad 		{
    156  1.1  riastrad 			.addr = dvo->slave_addr,
    157  1.1  riastrad 			.flags = I2C_M_RD,
    158  1.1  riastrad 			.len = 1,
    159  1.1  riastrad 			.buf = in_buf,
    160  1.1  riastrad 		}
    161  1.1  riastrad 	};
    162  1.1  riastrad 
    163  1.1  riastrad 	out_buf[0] = addr;
    164  1.1  riastrad 	out_buf[1] = 0;
    165  1.1  riastrad 
    166  1.1  riastrad 	if (i2c_transfer(adapter, msgs, 2) == 2) {
    167  1.1  riastrad 		*ch = in_buf[0];
    168  1.1  riastrad 		return true;
    169  1.1  riastrad 	}
    170  1.1  riastrad 
    171  1.1  riastrad 	if (!ch7xxx->quiet) {
    172  1.1  riastrad 		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
    173  1.1  riastrad 			  addr, adapter->name, dvo->slave_addr);
    174  1.1  riastrad 	}
    175  1.1  riastrad 	return false;
    176  1.1  riastrad }
    177  1.1  riastrad 
    178  1.1  riastrad /** Writes an 8 bit register */
    179  1.1  riastrad static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
    180  1.1  riastrad {
    181  1.1  riastrad 	struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
    182  1.1  riastrad 	struct i2c_adapter *adapter = dvo->i2c_bus;
    183  1.1  riastrad 	u8 out_buf[2];
    184  1.1  riastrad 	struct i2c_msg msg = {
    185  1.1  riastrad 		.addr = dvo->slave_addr,
    186  1.1  riastrad 		.flags = 0,
    187  1.1  riastrad 		.len = 2,
    188  1.1  riastrad 		.buf = out_buf,
    189  1.1  riastrad 	};
    190  1.1  riastrad 
    191  1.1  riastrad 	out_buf[0] = addr;
    192  1.1  riastrad 	out_buf[1] = ch;
    193  1.1  riastrad 
    194  1.1  riastrad 	if (i2c_transfer(adapter, &msg, 1) == 1)
    195  1.1  riastrad 		return true;
    196  1.1  riastrad 
    197  1.1  riastrad 	if (!ch7xxx->quiet) {
    198  1.1  riastrad 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
    199  1.1  riastrad 			  addr, adapter->name, dvo->slave_addr);
    200  1.1  riastrad 	}
    201  1.1  riastrad 
    202  1.1  riastrad 	return false;
    203  1.1  riastrad }
    204  1.1  riastrad 
    205  1.1  riastrad static bool ch7xxx_init(struct intel_dvo_device *dvo,
    206  1.1  riastrad 			struct i2c_adapter *adapter)
    207  1.1  riastrad {
    208  1.1  riastrad 	/* this will detect the CH7xxx chip on the specified i2c bus */
    209  1.1  riastrad 	struct ch7xxx_priv *ch7xxx;
    210  1.1  riastrad 	u8 vendor, device;
    211  1.2  riastrad 	const char *name, *devid;
    212  1.1  riastrad 
    213  1.1  riastrad 	ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
    214  1.1  riastrad 	if (ch7xxx == NULL)
    215  1.1  riastrad 		return false;
    216  1.1  riastrad 
    217  1.1  riastrad 	dvo->i2c_bus = adapter;
    218  1.1  riastrad 	dvo->dev_priv = ch7xxx;
    219  1.1  riastrad 	ch7xxx->quiet = true;
    220  1.1  riastrad 
    221  1.1  riastrad 	if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
    222  1.1  riastrad 		goto out;
    223  1.1  riastrad 
    224  1.1  riastrad 	name = ch7xxx_get_id(vendor);
    225  1.1  riastrad 	if (!name) {
    226  1.1  riastrad 		DRM_DEBUG_KMS("ch7xxx not detected; got VID 0x%02x from %s slave %d.\n",
    227  1.1  riastrad 			      vendor, adapter->name, dvo->slave_addr);
    228  1.1  riastrad 		goto out;
    229  1.1  riastrad 	}
    230  1.1  riastrad 
    231  1.1  riastrad 
    232  1.1  riastrad 	if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
    233  1.1  riastrad 		goto out;
    234  1.1  riastrad 
    235  1.1  riastrad 	devid = ch7xxx_get_did(device);
    236  1.1  riastrad 	if (!devid) {
    237  1.1  riastrad 		DRM_DEBUG_KMS("ch7xxx not detected; got DID 0x%02x from %s slave %d.\n",
    238  1.1  riastrad 			      device, adapter->name, dvo->slave_addr);
    239  1.1  riastrad 		goto out;
    240  1.1  riastrad 	}
    241  1.1  riastrad 
    242  1.1  riastrad 	ch7xxx->quiet = false;
    243  1.1  riastrad 	DRM_DEBUG_KMS("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
    244  1.1  riastrad 		  name, vendor, device);
    245  1.1  riastrad 	return true;
    246  1.1  riastrad out:
    247  1.1  riastrad 	kfree(ch7xxx);
    248  1.1  riastrad 	return false;
    249  1.1  riastrad }
    250  1.1  riastrad 
    251  1.1  riastrad static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
    252  1.1  riastrad {
    253  1.1  riastrad 	u8 cdet, orig_pm, pm;
    254  1.1  riastrad 
    255  1.1  riastrad 	ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
    256  1.1  riastrad 
    257  1.1  riastrad 	pm = orig_pm;
    258  1.1  riastrad 	pm &= ~CH7xxx_PM_FPD;
    259  1.1  riastrad 	pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
    260  1.1  riastrad 
    261  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_PM, pm);
    262  1.1  riastrad 
    263  1.1  riastrad 	ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
    264  1.1  riastrad 
    265  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
    266  1.1  riastrad 
    267  1.1  riastrad 	if (cdet & CH7xxx_CDET_DVI)
    268  1.1  riastrad 		return connector_status_connected;
    269  1.1  riastrad 	return connector_status_disconnected;
    270  1.1  riastrad }
    271  1.1  riastrad 
    272  1.1  riastrad static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
    273  1.1  riastrad 					      struct drm_display_mode *mode)
    274  1.1  riastrad {
    275  1.1  riastrad 	if (mode->clock > 165000)
    276  1.1  riastrad 		return MODE_CLOCK_HIGH;
    277  1.1  riastrad 
    278  1.1  riastrad 	return MODE_OK;
    279  1.1  riastrad }
    280  1.1  riastrad 
    281  1.1  riastrad static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
    282  1.1  riastrad 			    const struct drm_display_mode *mode,
    283  1.1  riastrad 			    const struct drm_display_mode *adjusted_mode)
    284  1.1  riastrad {
    285  1.1  riastrad 	u8 tvco, tpcp, tpd, tlpf, idf;
    286  1.1  riastrad 
    287  1.1  riastrad 	if (mode->clock <= 65000) {
    288  1.1  riastrad 		tvco = 0x23;
    289  1.1  riastrad 		tpcp = 0x08;
    290  1.1  riastrad 		tpd = 0x16;
    291  1.1  riastrad 		tlpf = 0x60;
    292  1.1  riastrad 	} else {
    293  1.1  riastrad 		tvco = 0x2d;
    294  1.1  riastrad 		tpcp = 0x06;
    295  1.1  riastrad 		tpd = 0x26;
    296  1.1  riastrad 		tlpf = 0xa0;
    297  1.1  riastrad 	}
    298  1.1  riastrad 
    299  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
    300  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
    301  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
    302  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
    303  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
    304  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
    305  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
    306  1.1  riastrad 
    307  1.1  riastrad 	ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
    308  1.1  riastrad 
    309  1.1  riastrad 	idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
    310  1.1  riastrad 	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
    311  1.1  riastrad 		idf |= CH7xxx_IDF_HSP;
    312  1.1  riastrad 
    313  1.1  riastrad 	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
    314  1.1  riastrad 		idf |= CH7xxx_IDF_VSP;
    315  1.1  riastrad 
    316  1.1  riastrad 	ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
    317  1.1  riastrad }
    318  1.1  riastrad 
    319  1.1  riastrad /* set the CH7xxx power state */
    320  1.1  riastrad static void ch7xxx_dpms(struct intel_dvo_device *dvo, bool enable)
    321  1.1  riastrad {
    322  1.1  riastrad 	if (enable)
    323  1.1  riastrad 		ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
    324  1.1  riastrad 	else
    325  1.1  riastrad 		ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
    326  1.1  riastrad }
    327  1.1  riastrad 
    328  1.1  riastrad static bool ch7xxx_get_hw_state(struct intel_dvo_device *dvo)
    329  1.1  riastrad {
    330  1.1  riastrad 	u8 val;
    331  1.1  riastrad 
    332  1.1  riastrad 	ch7xxx_readb(dvo, CH7xxx_PM, &val);
    333  1.1  riastrad 
    334  1.1  riastrad 	if (val & (CH7xxx_PM_DVIL | CH7xxx_PM_DVIP))
    335  1.1  riastrad 		return true;
    336  1.1  riastrad 	else
    337  1.1  riastrad 		return false;
    338  1.1  riastrad }
    339  1.1  riastrad 
    340  1.1  riastrad static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
    341  1.1  riastrad {
    342  1.1  riastrad 	int i;
    343  1.1  riastrad 
    344  1.1  riastrad 	for (i = 0; i < CH7xxx_NUM_REGS; i++) {
    345  1.1  riastrad 		u8 val;
    346  1.1  riastrad 		if ((i % 8) == 0)
    347  1.1  riastrad 			DRM_DEBUG_KMS("\n %02X: ", i);
    348  1.1  riastrad 		ch7xxx_readb(dvo, i, &val);
    349  1.1  riastrad 		DRM_DEBUG_KMS("%02X ", val);
    350  1.1  riastrad 	}
    351  1.1  riastrad }
    352  1.1  riastrad 
    353  1.1  riastrad static void ch7xxx_destroy(struct intel_dvo_device *dvo)
    354  1.1  riastrad {
    355  1.1  riastrad 	struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
    356  1.1  riastrad 
    357  1.1  riastrad 	if (ch7xxx) {
    358  1.1  riastrad 		kfree(ch7xxx);
    359  1.1  riastrad 		dvo->dev_priv = NULL;
    360  1.1  riastrad 	}
    361  1.1  riastrad }
    362  1.1  riastrad 
    363  1.1  riastrad const struct intel_dvo_dev_ops ch7xxx_ops = {
    364  1.1  riastrad 	.init = ch7xxx_init,
    365  1.1  riastrad 	.detect = ch7xxx_detect,
    366  1.1  riastrad 	.mode_valid = ch7xxx_mode_valid,
    367  1.1  riastrad 	.mode_set = ch7xxx_mode_set,
    368  1.1  riastrad 	.dpms = ch7xxx_dpms,
    369  1.1  riastrad 	.get_hw_state = ch7xxx_get_hw_state,
    370  1.1  riastrad 	.dump_regs = ch7xxx_dump_regs,
    371  1.1  riastrad 	.destroy = ch7xxx_destroy,
    372  1.1  riastrad };
    373