cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sil164_drv.c (12086B)


      1/*
      2 * Copyright (C) 2010 Francisco Jerez.
      3 * All Rights Reserved.
      4 *
      5 * Permission is hereby granted, free of charge, to any person obtaining
      6 * a copy of this software and associated documentation files (the
      7 * "Software"), to deal in the Software without restriction, including
      8 * without limitation the rights to use, copy, modify, merge, publish,
      9 * distribute, sublicense, and/or sell copies of the Software, and to
     10 * permit persons to whom the Software is furnished to do so, subject to
     11 * the following conditions:
     12 *
     13 * The above copyright notice and this permission notice (including the
     14 * next paragraph) shall be included in all copies or substantial
     15 * portions of the Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
     21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24 *
     25 */
     26
     27#include <linux/module.h>
     28
     29#include <drm/drm_drv.h>
     30#include <drm/drm_encoder_slave.h>
     31#include <drm/drm_print.h>
     32#include <drm/drm_probe_helper.h>
     33#include <drm/i2c/sil164.h>
     34
     35struct sil164_priv {
     36	struct sil164_encoder_params config;
     37	struct i2c_client *duallink_slave;
     38
     39	uint8_t saved_state[0x10];
     40	uint8_t saved_slave_state[0x10];
     41};
     42
     43#define to_sil164_priv(x) \
     44	((struct sil164_priv *)to_encoder_slave(x)->slave_priv)
     45
     46#define sil164_dbg(client, format, ...) do {				\
     47		if (drm_debug_enabled(DRM_UT_KMS))			\
     48			dev_printk(KERN_DEBUG, &client->dev,		\
     49				   "%s: " format, __func__, ## __VA_ARGS__); \
     50	} while (0)
     51#define sil164_info(client, format, ...)		\
     52	dev_info(&client->dev, format, __VA_ARGS__)
     53#define sil164_err(client, format, ...)			\
     54	dev_err(&client->dev, format, __VA_ARGS__)
     55
     56#define SIL164_I2C_ADDR_MASTER			0x38
     57#define SIL164_I2C_ADDR_SLAVE			0x39
     58
     59/* HW register definitions */
     60
     61#define SIL164_VENDOR_LO			0x0
     62#define SIL164_VENDOR_HI			0x1
     63#define SIL164_DEVICE_LO			0x2
     64#define SIL164_DEVICE_HI			0x3
     65#define SIL164_REVISION				0x4
     66#define SIL164_FREQ_MIN				0x6
     67#define SIL164_FREQ_MAX				0x7
     68#define SIL164_CONTROL0				0x8
     69#  define SIL164_CONTROL0_POWER_ON		0x01
     70#  define SIL164_CONTROL0_EDGE_RISING		0x02
     71#  define SIL164_CONTROL0_INPUT_24BIT		0x04
     72#  define SIL164_CONTROL0_DUAL_EDGE		0x08
     73#  define SIL164_CONTROL0_HSYNC_ON		0x10
     74#  define SIL164_CONTROL0_VSYNC_ON		0x20
     75#define SIL164_DETECT				0x9
     76#  define SIL164_DETECT_INTR_STAT		0x01
     77#  define SIL164_DETECT_HOTPLUG_STAT		0x02
     78#  define SIL164_DETECT_RECEIVER_STAT		0x04
     79#  define SIL164_DETECT_INTR_MODE_RECEIVER	0x00
     80#  define SIL164_DETECT_INTR_MODE_HOTPLUG	0x08
     81#  define SIL164_DETECT_OUT_MODE_HIGH		0x00
     82#  define SIL164_DETECT_OUT_MODE_INTR		0x10
     83#  define SIL164_DETECT_OUT_MODE_RECEIVER	0x20
     84#  define SIL164_DETECT_OUT_MODE_HOTPLUG	0x30
     85#  define SIL164_DETECT_VSWING_STAT		0x80
     86#define SIL164_CONTROL1				0xa
     87#  define SIL164_CONTROL1_DESKEW_ENABLE		0x10
     88#  define SIL164_CONTROL1_DESKEW_INCR_SHIFT	5
     89#define SIL164_GPIO				0xb
     90#define SIL164_CONTROL2				0xc
     91#  define SIL164_CONTROL2_FILTER_ENABLE		0x01
     92#  define SIL164_CONTROL2_FILTER_SETTING_SHIFT	1
     93#  define SIL164_CONTROL2_DUALLINK_MASTER	0x40
     94#  define SIL164_CONTROL2_SYNC_CONT		0x80
     95#define SIL164_DUALLINK				0xd
     96#  define SIL164_DUALLINK_ENABLE		0x10
     97#  define SIL164_DUALLINK_SKEW_SHIFT		5
     98#define SIL164_PLLZONE				0xe
     99#  define SIL164_PLLZONE_STAT			0x08
    100#  define SIL164_PLLZONE_FORCE_ON		0x10
    101#  define SIL164_PLLZONE_FORCE_HIGH		0x20
    102
    103/* HW access functions */
    104
    105static void
    106sil164_write(struct i2c_client *client, uint8_t addr, uint8_t val)
    107{
    108	uint8_t buf[] = {addr, val};
    109	int ret;
    110
    111	ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
    112	if (ret < 0)
    113		sil164_err(client, "Error %d writing to subaddress 0x%x\n",
    114			   ret, addr);
    115}
    116
    117static uint8_t
    118sil164_read(struct i2c_client *client, uint8_t addr)
    119{
    120	uint8_t val;
    121	int ret;
    122
    123	ret = i2c_master_send(client, &addr, sizeof(addr));
    124	if (ret < 0)
    125		goto fail;
    126
    127	ret = i2c_master_recv(client, &val, sizeof(val));
    128	if (ret < 0)
    129		goto fail;
    130
    131	return val;
    132
    133fail:
    134	sil164_err(client, "Error %d reading from subaddress 0x%x\n",
    135		   ret, addr);
    136	return 0;
    137}
    138
    139static void
    140sil164_save_state(struct i2c_client *client, uint8_t *state)
    141{
    142	int i;
    143
    144	for (i = 0x8; i <= 0xe; i++)
    145		state[i] = sil164_read(client, i);
    146}
    147
    148static void
    149sil164_restore_state(struct i2c_client *client, uint8_t *state)
    150{
    151	int i;
    152
    153	for (i = 0x8; i <= 0xe; i++)
    154		sil164_write(client, i, state[i]);
    155}
    156
    157static void
    158sil164_set_power_state(struct i2c_client *client, bool on)
    159{
    160	uint8_t control0 = sil164_read(client, SIL164_CONTROL0);
    161
    162	if (on)
    163		control0 |= SIL164_CONTROL0_POWER_ON;
    164	else
    165		control0 &= ~SIL164_CONTROL0_POWER_ON;
    166
    167	sil164_write(client, SIL164_CONTROL0, control0);
    168}
    169
    170static void
    171sil164_init_state(struct i2c_client *client,
    172		  struct sil164_encoder_params *config,
    173		  bool duallink)
    174{
    175	sil164_write(client, SIL164_CONTROL0,
    176		     SIL164_CONTROL0_HSYNC_ON |
    177		     SIL164_CONTROL0_VSYNC_ON |
    178		     (config->input_edge ? SIL164_CONTROL0_EDGE_RISING : 0) |
    179		     (config->input_width ? SIL164_CONTROL0_INPUT_24BIT : 0) |
    180		     (config->input_dual ? SIL164_CONTROL0_DUAL_EDGE : 0));
    181
    182	sil164_write(client, SIL164_DETECT,
    183		     SIL164_DETECT_INTR_STAT |
    184		     SIL164_DETECT_OUT_MODE_RECEIVER);
    185
    186	sil164_write(client, SIL164_CONTROL1,
    187		     (config->input_skew ? SIL164_CONTROL1_DESKEW_ENABLE : 0) |
    188		     (((config->input_skew + 4) & 0x7)
    189		      << SIL164_CONTROL1_DESKEW_INCR_SHIFT));
    190
    191	sil164_write(client, SIL164_CONTROL2,
    192		     SIL164_CONTROL2_SYNC_CONT |
    193		     (config->pll_filter ? 0 : SIL164_CONTROL2_FILTER_ENABLE) |
    194		     (4 << SIL164_CONTROL2_FILTER_SETTING_SHIFT));
    195
    196	sil164_write(client, SIL164_PLLZONE, 0);
    197
    198	if (duallink)
    199		sil164_write(client, SIL164_DUALLINK,
    200			     SIL164_DUALLINK_ENABLE |
    201			     (((config->duallink_skew + 4) & 0x7)
    202			      << SIL164_DUALLINK_SKEW_SHIFT));
    203	else
    204		sil164_write(client, SIL164_DUALLINK, 0);
    205}
    206
    207/* DRM encoder functions */
    208
    209static void
    210sil164_encoder_set_config(struct drm_encoder *encoder, void *params)
    211{
    212	struct sil164_priv *priv = to_sil164_priv(encoder);
    213
    214	priv->config = *(struct sil164_encoder_params *)params;
    215}
    216
    217static void
    218sil164_encoder_dpms(struct drm_encoder *encoder, int mode)
    219{
    220	struct sil164_priv *priv = to_sil164_priv(encoder);
    221	bool on = (mode == DRM_MODE_DPMS_ON);
    222	bool duallink = (on && encoder->crtc->mode.clock > 165000);
    223
    224	sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on);
    225
    226	if (priv->duallink_slave)
    227		sil164_set_power_state(priv->duallink_slave, duallink);
    228}
    229
    230static void
    231sil164_encoder_save(struct drm_encoder *encoder)
    232{
    233	struct sil164_priv *priv = to_sil164_priv(encoder);
    234
    235	sil164_save_state(drm_i2c_encoder_get_client(encoder),
    236			  priv->saved_state);
    237
    238	if (priv->duallink_slave)
    239		sil164_save_state(priv->duallink_slave,
    240				  priv->saved_slave_state);
    241}
    242
    243static void
    244sil164_encoder_restore(struct drm_encoder *encoder)
    245{
    246	struct sil164_priv *priv = to_sil164_priv(encoder);
    247
    248	sil164_restore_state(drm_i2c_encoder_get_client(encoder),
    249			     priv->saved_state);
    250
    251	if (priv->duallink_slave)
    252		sil164_restore_state(priv->duallink_slave,
    253				     priv->saved_slave_state);
    254}
    255
    256static int
    257sil164_encoder_mode_valid(struct drm_encoder *encoder,
    258			  struct drm_display_mode *mode)
    259{
    260	struct sil164_priv *priv = to_sil164_priv(encoder);
    261
    262	if (mode->clock < 32000)
    263		return MODE_CLOCK_LOW;
    264
    265	if (mode->clock > 330000 ||
    266	    (mode->clock > 165000 && !priv->duallink_slave))
    267		return MODE_CLOCK_HIGH;
    268
    269	return MODE_OK;
    270}
    271
    272static void
    273sil164_encoder_mode_set(struct drm_encoder *encoder,
    274			struct drm_display_mode *mode,
    275			struct drm_display_mode *adjusted_mode)
    276{
    277	struct sil164_priv *priv = to_sil164_priv(encoder);
    278	bool duallink = adjusted_mode->clock > 165000;
    279
    280	sil164_init_state(drm_i2c_encoder_get_client(encoder),
    281			  &priv->config, duallink);
    282
    283	if (priv->duallink_slave)
    284		sil164_init_state(priv->duallink_slave,
    285				  &priv->config, duallink);
    286
    287	sil164_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
    288}
    289
    290static enum drm_connector_status
    291sil164_encoder_detect(struct drm_encoder *encoder,
    292		      struct drm_connector *connector)
    293{
    294	struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
    295
    296	if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT)
    297		return connector_status_connected;
    298	else
    299		return connector_status_disconnected;
    300}
    301
    302static int
    303sil164_encoder_get_modes(struct drm_encoder *encoder,
    304			 struct drm_connector *connector)
    305{
    306	return 0;
    307}
    308
    309static int
    310sil164_encoder_create_resources(struct drm_encoder *encoder,
    311				struct drm_connector *connector)
    312{
    313	return 0;
    314}
    315
    316static int
    317sil164_encoder_set_property(struct drm_encoder *encoder,
    318			    struct drm_connector *connector,
    319			    struct drm_property *property,
    320			    uint64_t val)
    321{
    322	return 0;
    323}
    324
    325static void
    326sil164_encoder_destroy(struct drm_encoder *encoder)
    327{
    328	struct sil164_priv *priv = to_sil164_priv(encoder);
    329
    330	i2c_unregister_device(priv->duallink_slave);
    331
    332	kfree(priv);
    333	drm_i2c_encoder_destroy(encoder);
    334}
    335
    336static const struct drm_encoder_slave_funcs sil164_encoder_funcs = {
    337	.set_config = sil164_encoder_set_config,
    338	.destroy = sil164_encoder_destroy,
    339	.dpms = sil164_encoder_dpms,
    340	.save = sil164_encoder_save,
    341	.restore = sil164_encoder_restore,
    342	.mode_valid = sil164_encoder_mode_valid,
    343	.mode_set = sil164_encoder_mode_set,
    344	.detect = sil164_encoder_detect,
    345	.get_modes = sil164_encoder_get_modes,
    346	.create_resources = sil164_encoder_create_resources,
    347	.set_property = sil164_encoder_set_property,
    348};
    349
    350/* I2C driver functions */
    351
    352static int
    353sil164_probe(struct i2c_client *client, const struct i2c_device_id *id)
    354{
    355	int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 |
    356		sil164_read(client, SIL164_VENDOR_LO);
    357	int device = sil164_read(client, SIL164_DEVICE_HI) << 8 |
    358		sil164_read(client, SIL164_DEVICE_LO);
    359	int rev = sil164_read(client, SIL164_REVISION);
    360
    361	if (vendor != 0x1 || device != 0x6) {
    362		sil164_dbg(client, "Unknown device %x:%x.%x\n",
    363			   vendor, device, rev);
    364		return -ENODEV;
    365	}
    366
    367	sil164_info(client, "Detected device %x:%x.%x\n",
    368		    vendor, device, rev);
    369
    370	return 0;
    371}
    372
    373static int
    374sil164_remove(struct i2c_client *client)
    375{
    376	return 0;
    377}
    378
    379static struct i2c_client *
    380sil164_detect_slave(struct i2c_client *client)
    381{
    382	struct i2c_adapter *adap = client->adapter;
    383	struct i2c_msg msg = {
    384		.addr = SIL164_I2C_ADDR_SLAVE,
    385		.len = 0,
    386	};
    387	const struct i2c_board_info info = {
    388		I2C_BOARD_INFO("sil164", SIL164_I2C_ADDR_SLAVE)
    389	};
    390
    391	if (i2c_transfer(adap, &msg, 1) != 1) {
    392		sil164_dbg(adap, "No dual-link slave found.");
    393		return NULL;
    394	}
    395
    396	return i2c_new_client_device(adap, &info);
    397}
    398
    399static int
    400sil164_encoder_init(struct i2c_client *client,
    401		    struct drm_device *dev,
    402		    struct drm_encoder_slave *encoder)
    403{
    404	struct sil164_priv *priv;
    405	struct i2c_client *slave_client;
    406
    407	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    408	if (!priv)
    409		return -ENOMEM;
    410
    411	encoder->slave_priv = priv;
    412	encoder->slave_funcs = &sil164_encoder_funcs;
    413
    414	slave_client = sil164_detect_slave(client);
    415	if (!IS_ERR(slave_client))
    416		priv->duallink_slave = slave_client;
    417
    418	return 0;
    419}
    420
    421static const struct i2c_device_id sil164_ids[] = {
    422	{ "sil164", 0 },
    423	{ }
    424};
    425MODULE_DEVICE_TABLE(i2c, sil164_ids);
    426
    427static struct drm_i2c_encoder_driver sil164_driver = {
    428	.i2c_driver = {
    429		.probe = sil164_probe,
    430		.remove = sil164_remove,
    431		.driver = {
    432			.name = "sil164",
    433		},
    434		.id_table = sil164_ids,
    435	},
    436	.encoder_init = sil164_encoder_init,
    437};
    438
    439/* Module initialization */
    440
    441static int __init
    442sil164_init(void)
    443{
    444	return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver);
    445}
    446
    447static void __exit
    448sil164_exit(void)
    449{
    450	drm_i2c_encoder_unregister(&sil164_driver);
    451}
    452
    453MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
    454MODULE_DESCRIPTION("Silicon Image sil164 TMDS transmitter driver");
    455MODULE_LICENSE("GPL and additional rights");
    456
    457module_init(sil164_init);
    458module_exit(sil164_exit);