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

ddk750_swi2c.c (12892B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
      4 *
      5 *  swi2c.c --- SM750/SM718 DDK
      6 *  This file contains the source code for I2C using software
      7 *  implementation.
      8 */
      9
     10#include "ddk750_chip.h"
     11#include "ddk750_reg.h"
     12#include "ddk750_swi2c.h"
     13#include "ddk750_power.h"
     14
     15/*
     16 * I2C Software Master Driver:
     17 * ===========================
     18 * Each i2c cycle is split into 4 sections. Each of these section marks
     19 * a point in time where the SCL or SDA may be changed.
     20 *
     21 * 1 Cycle == |  Section I. |  Section 2. |  Section 3. |  Section 4. |
     22 *            +-------------+-------------+-------------+-------------+
     23 *            | SCL set LOW |SCL no change| SCL set HIGH|SCL no change|
     24 *
     25 *                                          ____________ _____________
     26 * SCL == XXXX _____________ ____________ /
     27 *
     28 * I.e. the SCL may only be changed in section 1. and section 3. while
     29 * the SDA may only be changed in section 2. and section 4. The table
     30 * below gives the changes for these 2 lines in the varios sections.
     31 *
     32 * Section changes Table:
     33 * ======================
     34 * blank = no change, L = set bit LOW, H = set bit HIGH
     35 *
     36 *                                | 1.| 2.| 3.| 4.|
     37 *                 ---------------+---+---+---+---+
     38 *                 Tx Start   SDA |   | H |   | L |
     39 *                            SCL | L |   | H |   |
     40 *                 ---------------+---+---+---+---+
     41 *                 Tx Stop    SDA |   | L |   | H |
     42 *                            SCL | L |   | H |   |
     43 *                 ---------------+---+---+---+---+
     44 *                 Tx bit H   SDA |   | H |   |   |
     45 *                            SCL | L |   | H |   |
     46 *                 ---------------+---+---+---+---+
     47 *                 Tx bit L   SDA |   | L |   |   |
     48 *                            SCL | L |   | H |   |
     49 *                 ---------------+---+---+---+---+
     50 *
     51 */
     52
     53/* GPIO pins used for this I2C. It ranges from 0 to 63. */
     54static unsigned char sw_i2c_clk_gpio = DEFAULT_I2C_SCL;
     55static unsigned char sw_i2c_data_gpio = DEFAULT_I2C_SDA;
     56
     57/*
     58 *  Below is the variable declaration for the GPIO pin register usage
     59 *  for the i2c Clock and i2c Data.
     60 *
     61 *  Note:
     62 *      Notice that the GPIO usage for the i2c clock and i2c Data are
     63 *      separated. This is to make this code flexible enough when
     64 *      two separate GPIO pins for the clock and data are located
     65 *      in two different GPIO register set (worst case).
     66 */
     67
     68/* i2c Clock GPIO Register usage */
     69static unsigned long sw_i2c_clk_gpio_mux_reg = GPIO_MUX;
     70static unsigned long sw_i2c_clk_gpio_data_reg = GPIO_DATA;
     71static unsigned long sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION;
     72
     73/* i2c Data GPIO Register usage */
     74static unsigned long sw_i2c_data_gpio_mux_reg = GPIO_MUX;
     75static unsigned long sw_i2c_data_gpio_data_reg = GPIO_DATA;
     76static unsigned long sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION;
     77
     78/*
     79 *  This function puts a delay between command
     80 */
     81static void sw_i2c_wait(void)
     82{
     83	/* find a bug:
     84	 * peekIO method works well before suspend/resume
     85	 * but after suspend, peekIO(0x3ce,0x61) & 0x10
     86	 * always be non-zero,which makes the while loop
     87	 * never finish.
     88	 * use non-ultimate for loop below is safe
     89	 */
     90
     91    /* Change wait algorithm to use PCI bus clock,
     92     * it's more reliable than counter loop ..
     93     * write 0x61 to 0x3ce and read from 0x3cf
     94     */
     95	int i, tmp;
     96
     97	for (i = 0; i < 600; i++) {
     98		tmp = i;
     99		tmp += i;
    100	}
    101}
    102
    103/*
    104 *  This function set/reset the SCL GPIO pin
    105 *
    106 *  Parameters:
    107 *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
    108 *
    109 *  Notes:
    110 *      When setting SCL to high, just set the GPIO as input where the pull up
    111 *      resistor will pull the signal up. Do not use software to pull up the
    112 *      signal because the i2c will fail when other device try to drive the
    113 *      signal due to SM50x will drive the signal to always high.
    114 */
    115static void sw_i2c_scl(unsigned char value)
    116{
    117	unsigned long gpio_data;
    118	unsigned long gpio_dir;
    119
    120	gpio_dir = peek32(sw_i2c_clk_gpio_data_dir_reg);
    121	if (value) {    /* High */
    122		/*
    123		 * Set direction as input. This will automatically
    124		 * pull the signal up.
    125		 */
    126		gpio_dir &= ~(1 << sw_i2c_clk_gpio);
    127		poke32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir);
    128	} else {        /* Low */
    129		/* Set the signal down */
    130		gpio_data = peek32(sw_i2c_clk_gpio_data_reg);
    131		gpio_data &= ~(1 << sw_i2c_clk_gpio);
    132		poke32(sw_i2c_clk_gpio_data_reg, gpio_data);
    133
    134		/* Set direction as output */
    135		gpio_dir |= (1 << sw_i2c_clk_gpio);
    136		poke32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir);
    137	}
    138}
    139
    140/*
    141 *  This function set/reset the SDA GPIO pin
    142 *
    143 *  Parameters:
    144 *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
    145 *
    146 *  Notes:
    147 *      When setting SCL to high, just set the GPIO as input where the pull up
    148 *      resistor will pull the signal up. Do not use software to pull up the
    149 *      signal because the i2c will fail when other device try to drive the
    150 *      signal due to SM50x will drive the signal to always high.
    151 */
    152static void sw_i2c_sda(unsigned char value)
    153{
    154	unsigned long gpio_data;
    155	unsigned long gpio_dir;
    156
    157	gpio_dir = peek32(sw_i2c_data_gpio_data_dir_reg);
    158	if (value) {    /* High */
    159		/*
    160		 * Set direction as input. This will automatically
    161		 * pull the signal up.
    162		 */
    163		gpio_dir &= ~(1 << sw_i2c_data_gpio);
    164		poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
    165	} else {        /* Low */
    166		/* Set the signal down */
    167		gpio_data = peek32(sw_i2c_data_gpio_data_reg);
    168		gpio_data &= ~(1 << sw_i2c_data_gpio);
    169		poke32(sw_i2c_data_gpio_data_reg, gpio_data);
    170
    171		/* Set direction as output */
    172		gpio_dir |= (1 << sw_i2c_data_gpio);
    173		poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
    174	}
    175}
    176
    177/*
    178 *  This function read the data from the SDA GPIO pin
    179 *
    180 *  Return Value:
    181 *      The SDA data bit sent by the Slave
    182 */
    183static unsigned char sw_i2c_read_sda(void)
    184{
    185	unsigned long gpio_dir;
    186	unsigned long gpio_data;
    187	unsigned long dir_mask = 1 << sw_i2c_data_gpio;
    188
    189	/* Make sure that the direction is input (High) */
    190	gpio_dir = peek32(sw_i2c_data_gpio_data_dir_reg);
    191	if ((gpio_dir & dir_mask) != ~dir_mask) {
    192		gpio_dir &= ~(1 << sw_i2c_data_gpio);
    193		poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
    194	}
    195
    196	/* Now read the SDA line */
    197	gpio_data = peek32(sw_i2c_data_gpio_data_reg);
    198	if (gpio_data & (1 << sw_i2c_data_gpio))
    199		return 1;
    200	else
    201		return 0;
    202}
    203
    204/*
    205 *  This function sends ACK signal
    206 */
    207static void sw_i2c_ack(void)
    208{
    209	return;  /* Single byte read is ok without it. */
    210}
    211
    212/*
    213 *  This function sends the start command to the slave device
    214 */
    215static void sw_i2c_start(void)
    216{
    217	/* Start I2C */
    218	sw_i2c_sda(1);
    219	sw_i2c_scl(1);
    220	sw_i2c_sda(0);
    221}
    222
    223/*
    224 *  This function sends the stop command to the slave device
    225 */
    226static void sw_i2c_stop(void)
    227{
    228	/* Stop the I2C */
    229	sw_i2c_scl(1);
    230	sw_i2c_sda(0);
    231	sw_i2c_sda(1);
    232}
    233
    234/*
    235 *  This function writes one byte to the slave device
    236 *
    237 *  Parameters:
    238 *      data    - Data to be write to the slave device
    239 *
    240 *  Return Value:
    241 *       0   - Success
    242 *      -1   - Fail to write byte
    243 */
    244static long sw_i2c_write_byte(unsigned char data)
    245{
    246	unsigned char value = data;
    247	int i;
    248
    249	/* Sending the data bit by bit */
    250	for (i = 0; i < 8; i++) {
    251		/* Set SCL to low */
    252		sw_i2c_scl(0);
    253
    254		/* Send data bit */
    255		if ((value & 0x80) != 0)
    256			sw_i2c_sda(1);
    257		else
    258			sw_i2c_sda(0);
    259
    260		sw_i2c_wait();
    261
    262		/* Toggle clk line to one */
    263		sw_i2c_scl(1);
    264		sw_i2c_wait();
    265
    266		/* Shift byte to be sent */
    267		value = value << 1;
    268	}
    269
    270	/* Set the SCL Low and SDA High (prepare to get input) */
    271	sw_i2c_scl(0);
    272	sw_i2c_sda(1);
    273
    274	/* Set the SCL High for ack */
    275	sw_i2c_wait();
    276	sw_i2c_scl(1);
    277	sw_i2c_wait();
    278
    279	/* Read SDA, until SDA==0 */
    280	for (i = 0; i < 0xff; i++) {
    281		if (!sw_i2c_read_sda())
    282			break;
    283
    284		sw_i2c_scl(0);
    285		sw_i2c_wait();
    286		sw_i2c_scl(1);
    287		sw_i2c_wait();
    288	}
    289
    290	/* Set the SCL Low and SDA High */
    291	sw_i2c_scl(0);
    292	sw_i2c_sda(1);
    293
    294	if (i < 0xff)
    295		return 0;
    296	else
    297		return -1;
    298}
    299
    300/*
    301 *  This function reads one byte from the slave device
    302 *
    303 *  Parameters:
    304 *      ack    - Flag to indicate either to send the acknowledge
    305 *            message to the slave device or not
    306 *
    307 *  Return Value:
    308 *      One byte data read from the Slave device
    309 */
    310static unsigned char sw_i2c_read_byte(unsigned char ack)
    311{
    312	int i;
    313	unsigned char data = 0;
    314
    315	for (i = 7; i >= 0; i--) {
    316		/* Set the SCL to Low and SDA to High (Input) */
    317		sw_i2c_scl(0);
    318		sw_i2c_sda(1);
    319		sw_i2c_wait();
    320
    321		/* Set the SCL High */
    322		sw_i2c_scl(1);
    323		sw_i2c_wait();
    324
    325		/* Read data bits from SDA */
    326		data |= (sw_i2c_read_sda() << i);
    327	}
    328
    329	if (ack)
    330		sw_i2c_ack();
    331
    332	/* Set the SCL Low and SDA High */
    333	sw_i2c_scl(0);
    334	sw_i2c_sda(1);
    335
    336	return data;
    337}
    338
    339/*
    340 * This function initializes GPIO port for SW I2C communication.
    341 *
    342 * Parameters:
    343 *      clk_gpio      - The GPIO pin to be used as i2c SCL
    344 *      data_gpio     - The GPIO pin to be used as i2c SDA
    345 *
    346 * Return Value:
    347 *      -1   - Fail to initialize the i2c
    348 *       0   - Success
    349 */
    350static long sm750le_i2c_init(unsigned char clk_gpio, unsigned char data_gpio)
    351{
    352	int i;
    353
    354	/* Initialize the GPIO pin for the i2c Clock Register */
    355	sw_i2c_clk_gpio_data_reg = GPIO_DATA_SM750LE;
    356	sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION_SM750LE;
    357
    358	/* Initialize the Clock GPIO Offset */
    359	sw_i2c_clk_gpio = clk_gpio;
    360
    361	/* Initialize the GPIO pin for the i2c Data Register */
    362	sw_i2c_data_gpio_data_reg = GPIO_DATA_SM750LE;
    363	sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION_SM750LE;
    364
    365	/* Initialize the Data GPIO Offset */
    366	sw_i2c_data_gpio = data_gpio;
    367
    368	/* Note that SM750LE don't have GPIO MUX and power is always on */
    369
    370	/* Clear the i2c lines. */
    371	for (i = 0; i < 9; i++)
    372		sw_i2c_stop();
    373
    374	return 0;
    375}
    376
    377/*
    378 * This function initializes the i2c attributes and bus
    379 *
    380 * Parameters:
    381 *      clk_gpio      - The GPIO pin to be used as i2c SCL
    382 *      data_gpio     - The GPIO pin to be used as i2c SDA
    383 *
    384 * Return Value:
    385 *      -1   - Fail to initialize the i2c
    386 *       0   - Success
    387 */
    388long sm750_sw_i2c_init(unsigned char clk_gpio, unsigned char data_gpio)
    389{
    390	int i;
    391
    392	/*
    393	 * Return 0 if the GPIO pins to be used is out of range. The
    394	 * range is only from [0..63]
    395	 */
    396	if ((clk_gpio > 31) || (data_gpio > 31))
    397		return -1;
    398
    399	if (sm750_get_chip_type() == SM750LE)
    400		return sm750le_i2c_init(clk_gpio, data_gpio);
    401
    402	/* Initialize the GPIO pin for the i2c Clock Register */
    403	sw_i2c_clk_gpio_mux_reg = GPIO_MUX;
    404	sw_i2c_clk_gpio_data_reg = GPIO_DATA;
    405	sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION;
    406
    407	/* Initialize the Clock GPIO Offset */
    408	sw_i2c_clk_gpio = clk_gpio;
    409
    410	/* Initialize the GPIO pin for the i2c Data Register */
    411	sw_i2c_data_gpio_mux_reg = GPIO_MUX;
    412	sw_i2c_data_gpio_data_reg = GPIO_DATA;
    413	sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION;
    414
    415	/* Initialize the Data GPIO Offset */
    416	sw_i2c_data_gpio = data_gpio;
    417
    418	/* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
    419	poke32(sw_i2c_clk_gpio_mux_reg,
    420	       peek32(sw_i2c_clk_gpio_mux_reg) & ~(1 << sw_i2c_clk_gpio));
    421	poke32(sw_i2c_data_gpio_mux_reg,
    422	       peek32(sw_i2c_data_gpio_mux_reg) & ~(1 << sw_i2c_data_gpio));
    423
    424	/* Enable GPIO power */
    425	sm750_enable_gpio(1);
    426
    427	/* Clear the i2c lines. */
    428	for (i = 0; i < 9; i++)
    429		sw_i2c_stop();
    430
    431	return 0;
    432}
    433
    434/*
    435 *  This function reads the slave device's register
    436 *
    437 *  Parameters:
    438 *      addr   - i2c Slave device address which register
    439 *                        to be read from
    440 *      reg    - Slave device's register to be read
    441 *
    442 *  Return Value:
    443 *      Register value
    444 */
    445unsigned char sm750_sw_i2c_read_reg(unsigned char addr, unsigned char reg)
    446{
    447	unsigned char data;
    448
    449	/* Send the Start signal */
    450	sw_i2c_start();
    451
    452	/* Send the device address */
    453	sw_i2c_write_byte(addr);
    454
    455	/* Send the register index */
    456	sw_i2c_write_byte(reg);
    457
    458	/* Get the bus again and get the data from the device read address */
    459	sw_i2c_start();
    460	sw_i2c_write_byte(addr + 1);
    461	data = sw_i2c_read_byte(1);
    462
    463	/* Stop swI2C and release the bus */
    464	sw_i2c_stop();
    465
    466	return data;
    467}
    468
    469/*
    470 *  This function writes a value to the slave device's register
    471 *
    472 *  Parameters:
    473 *      addr            - i2c Slave device address which register
    474 *                        to be written
    475 *      reg             - Slave device's register to be written
    476 *      data            - Data to be written to the register
    477 *
    478 *  Result:
    479 *          0   - Success
    480 *         -1   - Fail
    481 */
    482long sm750_sw_i2c_write_reg(unsigned char addr,
    483			    unsigned char reg,
    484			    unsigned char data)
    485{
    486	long ret = 0;
    487
    488	/* Send the Start signal */
    489	sw_i2c_start();
    490
    491	/* Send the device address and read the data. All should return success
    492	 * in order for the writing processed to be successful
    493	 */
    494	if ((sw_i2c_write_byte(addr) != 0) ||
    495	    (sw_i2c_write_byte(reg) != 0) ||
    496	    (sw_i2c_write_byte(data) != 0)) {
    497		ret = -1;
    498	}
    499
    500	/* Stop i2c and release the bus */
    501	sw_i2c_stop();
    502
    503	return ret;
    504}