2010-04-26 21:13:05 +04:00
/*
* intel_scu_ipc . c : Driver for the Intel SCU IPC mechanism
*
2015-01-21 22:38:09 +03:00
* ( C ) Copyright 2008 - 2010 , 2015 Intel Corporation
2010-04-26 21:13:05 +04:00
* Author : Sreedhara DS ( sreedhara . ds @ intel . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; version 2
* of the License .
*
2011-03-17 23:18:22 +03:00
* SCU running in ARC processor communicates with other entity running in IA
2010-04-26 21:13:05 +04:00
* core through IPC mechanism which in turn messaging between IA core ad SCU .
* SCU has two IPC mechanism IPC - 1 and IPC - 2. IPC - 1 is used between IA32 and
* SCU where IPC - 2 is used between P - Unit and SCU . This driver delas with
* IPC - 1 Driver provides an API for power control unit registers ( e . g . MSIC )
* along with other APIs .
*/
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/init.h>
2011-12-22 04:26:03 +04:00
# include <linux/device.h>
2010-04-26 21:13:05 +04:00
# include <linux/pm.h>
# include <linux/pci.h>
# include <linux/interrupt.h>
2010-09-13 18:55:05 +04:00
# include <linux/sfi.h>
2013-10-18 02:35:27 +04:00
# include <asm/intel-mid.h>
2010-04-26 21:13:05 +04:00
# include <asm/intel_scu_ipc.h>
/* IPC defines the following message types */
# define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
# define IPCMSG_BATTERY 0xEF /* Coulomb Counter Accumulator */
# define IPCMSG_FW_UPDATE 0xFE /* Firmware update */
# define IPCMSG_PCNTRL 0xFF /* Power controller unit read/write */
# define IPCMSG_FW_REVISION 0xF4 /* Get firmware revision */
/* Command id associated with message IPCMSG_PCNTRL */
# define IPC_CMD_PCNTRL_W 0 /* Register write */
# define IPC_CMD_PCNTRL_R 1 /* Register read */
# define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */
/*
* IPC register summary
*
2015-01-21 22:38:11 +03:00
* IPC register blocks are memory mapped at fixed address of PCI BAR 0.
2010-04-26 21:13:05 +04:00
* To read or write information to the SCU , driver writes to IPC - 1 memory
2015-01-21 22:38:11 +03:00
* mapped registers . The following is the IPC mechanism
2010-04-26 21:13:05 +04:00
*
* 1. IA core cDMI interface claims this transaction and converts it to a
* Transaction Layer Packet ( TLP ) message which is sent across the cDMI .
*
* 2. South Complex cDMI block receives this message and writes it to
* the IPC - 1 register block , causing an interrupt to the SCU
*
* 3. SCU firmware decodes this interrupt and IPC message and the appropriate
* message handler is called within firmware .
*/
2010-07-26 13:04:24 +04:00
# define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */
# define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */
2013-11-16 04:21:54 +04:00
# define IPC_IOC 0x100 /* IPC command register IOC bit */
2013-11-15 02:15:04 +04:00
2013-12-03 04:20:01 +04:00
# define PCI_DEVICE_ID_LINCROFT 0x082a
# define PCI_DEVICE_ID_PENWELL 0x080e
# define PCI_DEVICE_ID_CLOVERVIEW 0x08ea
# define PCI_DEVICE_ID_TANGIER 0x11a0
2015-01-21 22:38:09 +03:00
/* intel scu ipc driver data */
2013-11-15 02:15:04 +04:00
struct intel_scu_ipc_pdata_t {
u32 i2c_base ;
u32 i2c_len ;
2013-11-16 04:21:54 +04:00
u8 irq_mode ;
2013-11-15 02:15:04 +04:00
} ;
2013-12-03 04:20:00 +04:00
static struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = {
. i2c_base = 0xff12b000 ,
. i2c_len = 0x10 ,
. irq_mode = 0 ,
} ;
/* Penwell and Cloverview */
static struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = {
. i2c_base = 0xff12b000 ,
. i2c_len = 0x10 ,
. irq_mode = 1 ,
} ;
static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
. i2c_base = 0xff00d000 ,
. i2c_len = 0x10 ,
. irq_mode = 0 ,
2013-11-15 02:15:04 +04:00
} ;
2010-04-26 21:13:05 +04:00
struct intel_scu_ipc_dev {
2015-10-12 14:19:46 +03:00
struct device * dev ;
2010-04-26 21:13:05 +04:00
void __iomem * ipc_base ;
void __iomem * i2c_base ;
2013-11-16 04:21:54 +04:00
struct completion cmd_complete ;
u8 irq_mode ;
2010-04-26 21:13:05 +04:00
} ;
static struct intel_scu_ipc_dev ipcdev ; /* Only one for now */
/*
* IPC Read Buffer ( Read Only ) :
* 16 byte buffer for receiving data from SCU , if IPC command
* processing results in response data
*/
# define IPC_READ_BUFFER 0x90
# define IPC_I2C_CNTRL_ADDR 0
# define I2C_DATA_ADDR 0x04
static DEFINE_MUTEX ( ipclock ) ; /* lock used to prevent multiple call to SCU */
/*
2015-10-12 14:19:45 +03:00
* Send ipc command
2010-04-26 21:13:05 +04:00
* Command Register ( Write Only ) :
* A write to this register results in an interrupt to the SCU core processor
* Format :
* | rfu2 ( 8 ) | size ( 8 ) | command id ( 4 ) | rfu1 ( 3 ) | ioc ( 1 ) | command ( 8 ) |
*/
2015-10-12 14:19:45 +03:00
static inline void ipc_command ( struct intel_scu_ipc_dev * scu , u32 cmd )
2010-04-26 21:13:05 +04:00
{
2015-10-12 14:19:45 +03:00
if ( scu - > irq_mode ) {
reinit_completion ( & scu - > cmd_complete ) ;
writel ( cmd | IPC_IOC , scu - > ipc_base ) ;
2013-11-16 04:21:54 +04:00
}
2015-10-12 14:19:45 +03:00
writel ( cmd , scu - > ipc_base ) ;
2010-04-26 21:13:05 +04:00
}
/*
2015-10-12 14:19:45 +03:00
* Write ipc data
2010-04-26 21:13:05 +04:00
* IPC Write Buffer ( Write Only ) :
* 16 - byte buffer for sending data associated with IPC command to
* SCU . Size of the data is specified in the IPC_COMMAND_REG register
*/
2015-10-12 14:19:45 +03:00
static inline void ipc_data_writel ( struct intel_scu_ipc_dev * scu , u32 data , u32 offset )
2010-04-26 21:13:05 +04:00
{
2015-10-12 14:19:45 +03:00
writel ( data , scu - > ipc_base + 0x80 + offset ) ;
2010-04-26 21:13:05 +04:00
}
/*
* Status Register ( Read Only ) :
* Driver will read this register to get the ready / busy status of the IPC
* block and error status of the IPC command that was just processed by SCU
* Format :
* | rfu3 ( 8 ) | error code ( 8 ) | initiator id ( 8 ) | cmd id ( 4 ) | rfu1 ( 2 ) | error ( 1 ) | busy ( 1 ) |
*/
2015-10-12 14:19:45 +03:00
static inline u8 ipc_read_status ( struct intel_scu_ipc_dev * scu )
2010-04-26 21:13:05 +04:00
{
2015-10-12 14:19:45 +03:00
return __raw_readl ( scu - > ipc_base + 0x04 ) ;
2010-04-26 21:13:05 +04:00
}
2015-10-12 14:19:45 +03:00
/* Read ipc byte data */
static inline u8 ipc_data_readb ( struct intel_scu_ipc_dev * scu , u32 offset )
2010-04-26 21:13:05 +04:00
{
2015-10-12 14:19:45 +03:00
return readb ( scu - > ipc_base + IPC_READ_BUFFER + offset ) ;
2010-04-26 21:13:05 +04:00
}
2015-10-12 14:19:45 +03:00
/* Read ipc u32 data */
static inline u32 ipc_data_readl ( struct intel_scu_ipc_dev * scu , u32 offset )
2010-04-26 21:13:05 +04:00
{
2015-10-12 14:19:45 +03:00
return readl ( scu - > ipc_base + IPC_READ_BUFFER + offset ) ;
2010-04-26 21:13:05 +04:00
}
2015-01-21 22:38:09 +03:00
/* Wait till scu status is busy */
2015-10-12 14:19:45 +03:00
static inline int busy_loop ( struct intel_scu_ipc_dev * scu )
2010-04-26 21:13:05 +04:00
{
2015-10-12 14:19:45 +03:00
u32 status = ipc_read_status ( scu ) ;
2015-01-21 22:38:10 +03:00
u32 loop_count = 100000 ;
2010-04-26 21:13:05 +04:00
2015-01-21 22:38:10 +03:00
/* break if scu doesn't reset busy bit after huge retry */
while ( ( status & BIT ( 0 ) ) & & - - loop_count ) {
2010-04-26 21:13:05 +04:00
udelay ( 1 ) ; /* scu processing time is in few u secods */
2015-10-12 14:19:45 +03:00
status = ipc_read_status ( scu ) ;
2010-04-26 21:13:05 +04:00
}
2015-01-21 22:38:10 +03:00
if ( status & BIT ( 0 ) ) {
2015-10-12 14:19:46 +03:00
dev_err ( scu - > dev , " IPC timed out " ) ;
2015-01-21 22:38:10 +03:00
return - ETIMEDOUT ;
}
if ( status & BIT ( 1 ) )
2010-07-26 13:06:12 +04:00
return - EIO ;
return 0 ;
2010-04-26 21:13:05 +04:00
}
2013-11-16 04:21:54 +04:00
/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */
2015-10-12 14:19:45 +03:00
static inline int ipc_wait_for_interrupt ( struct intel_scu_ipc_dev * scu )
2013-11-16 04:21:54 +04:00
{
int status ;
2015-10-12 14:19:45 +03:00
if ( ! wait_for_completion_timeout ( & scu - > cmd_complete , 3 * HZ ) ) {
2015-10-12 14:19:46 +03:00
dev_err ( scu - > dev , " IPC timed out \n " ) ;
2013-11-16 04:21:54 +04:00
return - ETIMEDOUT ;
}
2015-10-12 14:19:45 +03:00
status = ipc_read_status ( scu ) ;
2015-01-21 22:38:10 +03:00
if ( status & BIT ( 1 ) )
2013-11-16 04:21:54 +04:00
return - EIO ;
return 0 ;
}
2015-10-12 14:19:45 +03:00
static int intel_scu_ipc_check_status ( struct intel_scu_ipc_dev * scu )
2013-11-16 04:21:54 +04:00
{
2015-10-12 14:19:45 +03:00
return scu - > irq_mode ? ipc_wait_for_interrupt ( scu ) : busy_loop ( scu ) ;
2013-11-16 04:21:54 +04:00
}
2010-04-26 21:13:05 +04:00
/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
static int pwr_reg_rdwr ( u16 * addr , u8 * data , u32 count , u32 op , u32 id )
{
2015-10-12 14:19:45 +03:00
struct intel_scu_ipc_dev * scu = & ipcdev ;
2012-03-06 03:01:02 +04:00
int nc ;
2010-04-26 21:13:05 +04:00
u32 offset = 0 ;
2011-01-25 17:12:12 +03:00
int err ;
2015-07-13 17:44:54 +03:00
u8 cbuf [ IPC_WWBUF_SIZE ] ;
2010-04-26 21:13:05 +04:00
u32 * wbuf = ( u32 * ) & cbuf ;
2010-07-26 13:04:37 +04:00
memset ( cbuf , 0 , sizeof ( cbuf ) ) ;
2015-07-13 17:44:54 +03:00
mutex_lock ( & ipclock ) ;
2015-10-12 14:19:46 +03:00
if ( scu - > dev = = NULL ) {
2010-04-26 21:13:05 +04:00
mutex_unlock ( & ipclock ) ;
return - ENODEV ;
}
2012-03-06 03:01:02 +04:00
for ( nc = 0 ; nc < count ; nc + + , offset + = 2 ) {
cbuf [ offset ] = addr [ nc ] ;
cbuf [ offset + 1 ] = addr [ nc ] > > 8 ;
}
2010-04-26 21:13:05 +04:00
2012-03-06 03:01:02 +04:00
if ( id = = IPC_CMD_PCNTRL_R ) {
for ( nc = 0 , offset = 0 ; nc < count ; nc + + , offset + = 4 )
2015-10-12 14:19:45 +03:00
ipc_data_writel ( scu , wbuf [ nc ] , offset ) ;
ipc_command ( scu , ( count * 2 ) < < 16 | id < < 12 | 0 < < 8 | op ) ;
2012-03-06 03:01:02 +04:00
} else if ( id = = IPC_CMD_PCNTRL_W ) {
for ( nc = 0 ; nc < count ; nc + + , offset + = 1 )
cbuf [ offset ] = data [ nc ] ;
for ( nc = 0 , offset = 0 ; nc < count ; nc + + , offset + = 4 )
2015-10-12 14:19:45 +03:00
ipc_data_writel ( scu , wbuf [ nc ] , offset ) ;
ipc_command ( scu , ( count * 3 ) < < 16 | id < < 12 | 0 < < 8 | op ) ;
2012-03-06 03:01:02 +04:00
} else if ( id = = IPC_CMD_PCNTRL_M ) {
cbuf [ offset ] = data [ 0 ] ;
cbuf [ offset + 1 ] = data [ 1 ] ;
2015-10-12 14:19:45 +03:00
ipc_data_writel ( scu , wbuf [ 0 ] , 0 ) ; /* Write wbuff */
ipc_command ( scu , 4 < < 16 | id < < 12 | 0 < < 8 | op ) ;
2010-07-26 13:02:46 +04:00
}
2010-04-26 21:13:05 +04:00
2015-10-12 14:19:45 +03:00
err = intel_scu_ipc_check_status ( scu ) ;
2013-11-15 02:15:06 +04:00
if ( ! err & & id = = IPC_CMD_PCNTRL_R ) { /* Read rbuf */
2010-04-26 21:13:05 +04:00
/* Workaround: values are read as 0 without memcpy_fromio */
2015-10-12 14:19:45 +03:00
memcpy_fromio ( cbuf , scu - > ipc_base + 0x90 , 16 ) ;
2012-03-06 03:01:02 +04:00
for ( nc = 0 ; nc < count ; nc + + )
2015-10-12 14:19:45 +03:00
data [ nc ] = ipc_data_readb ( scu , nc ) ;
2010-04-26 21:13:05 +04:00
}
mutex_unlock ( & ipclock ) ;
return err ;
}
/**
* intel_scu_ipc_ioread8 - read a word via the SCU
* @ addr : register on SCU
* @ data : return pointer for read byte
*
* Read a single register . Returns 0 on success or an error code . All
* locking between SCU accesses is handled for the caller .
*
* This function may sleep .
*/
int intel_scu_ipc_ioread8 ( u16 addr , u8 * data )
{
return pwr_reg_rdwr ( & addr , data , 1 , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_R ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_ioread8 ) ;
/**
* intel_scu_ipc_ioread16 - read a word via the SCU
* @ addr : register on SCU
* @ data : return pointer for read word
*
* Read a register pair . Returns 0 on success or an error code . All
* locking between SCU accesses is handled for the caller .
*
* This function may sleep .
*/
int intel_scu_ipc_ioread16 ( u16 addr , u16 * data )
{
2015-01-21 22:38:09 +03:00
u16 x [ 2 ] = { addr , addr + 1 } ;
2010-04-26 21:13:05 +04:00
return pwr_reg_rdwr ( x , ( u8 * ) data , 2 , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_R ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_ioread16 ) ;
/**
* intel_scu_ipc_ioread32 - read a dword via the SCU
* @ addr : register on SCU
* @ data : return pointer for read dword
*
* Read four registers . Returns 0 on success or an error code . All
* locking between SCU accesses is handled for the caller .
*
* This function may sleep .
*/
int intel_scu_ipc_ioread32 ( u16 addr , u32 * data )
{
u16 x [ 4 ] = { addr , addr + 1 , addr + 2 , addr + 3 } ;
return pwr_reg_rdwr ( x , ( u8 * ) data , 4 , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_R ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_ioread32 ) ;
/**
* intel_scu_ipc_iowrite8 - write a byte via the SCU
* @ addr : register on SCU
* @ data : byte to write
*
* Write a single register . Returns 0 on success or an error code . All
* locking between SCU accesses is handled for the caller .
*
* This function may sleep .
*/
int intel_scu_ipc_iowrite8 ( u16 addr , u8 data )
{
return pwr_reg_rdwr ( & addr , & data , 1 , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_W ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_iowrite8 ) ;
/**
* intel_scu_ipc_iowrite16 - write a word via the SCU
* @ addr : register on SCU
* @ data : word to write
*
* Write two registers . Returns 0 on success or an error code . All
* locking between SCU accesses is handled for the caller .
*
* This function may sleep .
*/
int intel_scu_ipc_iowrite16 ( u16 addr , u16 data )
{
2015-01-21 22:38:09 +03:00
u16 x [ 2 ] = { addr , addr + 1 } ;
2010-04-26 21:13:05 +04:00
return pwr_reg_rdwr ( x , ( u8 * ) & data , 2 , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_W ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_iowrite16 ) ;
/**
* intel_scu_ipc_iowrite32 - write a dword via the SCU
* @ addr : register on SCU
* @ data : dword to write
*
* Write four registers . Returns 0 on success or an error code . All
* locking between SCU accesses is handled for the caller .
*
* This function may sleep .
*/
int intel_scu_ipc_iowrite32 ( u16 addr , u32 data )
{
u16 x [ 4 ] = { addr , addr + 1 , addr + 2 , addr + 3 } ;
return pwr_reg_rdwr ( x , ( u8 * ) & data , 4 , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_W ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_iowrite32 ) ;
/**
* intel_scu_ipc_readvv - read a set of registers
* @ addr : register list
* @ data : bytes to return
* @ len : length of array
*
* Read registers . Returns 0 on success or an error code . All
* locking between SCU accesses is handled for the caller .
*
* The largest array length permitted by the hardware is 5 items .
*
* This function may sleep .
*/
int intel_scu_ipc_readv ( u16 * addr , u8 * data , int len )
{
return pwr_reg_rdwr ( addr , data , len , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_R ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_readv ) ;
/**
* intel_scu_ipc_writev - write a set of registers
* @ addr : register list
* @ data : bytes to write
* @ len : length of array
*
* Write registers . Returns 0 on success or an error code . All
* locking between SCU accesses is handled for the caller .
*
* The largest array length permitted by the hardware is 5 items .
*
* This function may sleep .
*
*/
int intel_scu_ipc_writev ( u16 * addr , u8 * data , int len )
{
return pwr_reg_rdwr ( addr , data , len , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_W ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_writev ) ;
/**
* intel_scu_ipc_update_register - r / m / w a register
* @ addr : register address
* @ bits : bits to update
* @ mask : mask of bits to update
*
* Read - modify - write power control unit register . The first data argument
* must be register value and second is mask value
* mask is a bitmap that indicates which bits to update .
* 0 = masked . Don ' t modify this bit , 1 = modify this bit .
* returns 0 on success or an error code .
*
* This function may sleep . Locking between SCU accesses is handled
* for the caller .
*/
int intel_scu_ipc_update_register ( u16 addr , u8 bits , u8 mask )
{
u8 data [ 2 ] = { bits , mask } ;
return pwr_reg_rdwr ( & addr , data , 1 , IPCMSG_PCNTRL , IPC_CMD_PCNTRL_M ) ;
}
EXPORT_SYMBOL ( intel_scu_ipc_update_register ) ;
/**
* intel_scu_ipc_simple_command - send a simple command
* @ cmd : command
* @ sub : sub type
*
* Issue a simple command to the SCU . Do not use this interface if
* you must then access data as any data values may be overwritten
* by another SCU access by the time this function returns .
*
* This function may sleep . Locking for SCU accesses is handled for
* the caller .
*/
int intel_scu_ipc_simple_command ( int cmd , int sub )
{
2015-10-12 14:19:45 +03:00
struct intel_scu_ipc_dev * scu = & ipcdev ;
2011-01-25 17:12:12 +03:00
int err ;
2010-04-26 21:13:05 +04:00
mutex_lock ( & ipclock ) ;
2015-10-12 14:19:46 +03:00
if ( scu - > dev = = NULL ) {
2010-04-26 21:13:05 +04:00
mutex_unlock ( & ipclock ) ;
return - ENODEV ;
}
2015-10-12 14:19:45 +03:00
ipc_command ( scu , sub < < 12 | cmd ) ;
err = intel_scu_ipc_check_status ( scu ) ;
2010-04-26 21:13:05 +04:00
mutex_unlock ( & ipclock ) ;
return err ;
}
EXPORT_SYMBOL ( intel_scu_ipc_simple_command ) ;
/**
* intel_scu_ipc_command - command with data
* @ cmd : command
* @ sub : sub type
* @ in : input data
2010-07-19 12:37:42 +04:00
* @ inlen : input length in dwords
2010-04-26 21:13:05 +04:00
* @ out : output data
2010-07-19 12:37:42 +04:00
* @ outlein : output length in dwords
2010-04-26 21:13:05 +04:00
*
* Issue a command to the SCU which involves data transfers . Do the
* data copies under the lock but leave it for the caller to interpret
*/
int intel_scu_ipc_command ( int cmd , int sub , u32 * in , int inlen ,
2015-01-21 22:38:09 +03:00
u32 * out , int outlen )
2010-04-26 21:13:05 +04:00
{
2015-10-12 14:19:45 +03:00
struct intel_scu_ipc_dev * scu = & ipcdev ;
2011-01-25 17:12:12 +03:00
int i , err ;
2010-04-26 21:13:05 +04:00
mutex_lock ( & ipclock ) ;
2015-10-12 14:19:46 +03:00
if ( scu - > dev = = NULL ) {
2010-04-26 21:13:05 +04:00
mutex_unlock ( & ipclock ) ;
return - ENODEV ;
}
for ( i = 0 ; i < inlen ; i + + )
2015-10-12 14:19:45 +03:00
ipc_data_writel ( scu , * in + + , 4 * i ) ;
2010-04-26 21:13:05 +04:00
2015-10-12 14:19:45 +03:00
ipc_command ( scu , ( inlen < < 16 ) | ( sub < < 12 ) | cmd ) ;
err = intel_scu_ipc_check_status ( scu ) ;
2010-04-26 21:13:05 +04:00
2013-11-15 02:15:06 +04:00
if ( ! err ) {
for ( i = 0 ; i < outlen ; i + + )
2015-10-12 14:19:45 +03:00
* out + + = ipc_data_readl ( scu , 4 * i ) ;
2013-11-15 02:15:06 +04:00
}
2010-04-26 21:13:05 +04:00
mutex_unlock ( & ipclock ) ;
return err ;
}
EXPORT_SYMBOL ( intel_scu_ipc_command ) ;
2015-01-21 22:38:09 +03:00
/* I2C commands */
2010-04-26 21:13:05 +04:00
# define IPC_I2C_WRITE 1 /* I2C Write command */
# define IPC_I2C_READ 2 /* I2C Read command */
/**
* intel_scu_ipc_i2c_cntrl - I2C read / write operations
* @ addr : I2C address + command bits
* @ data : data to read / write
*
* Perform an an I2C read / write operation via the SCU . All locking is
* handled for the caller . This function may sleep .
*
* Returns an error code or 0 on success .
*
* This has to be in the IPC driver for the locking .
*/
int intel_scu_ipc_i2c_cntrl ( u32 addr , u32 * data )
{
2015-10-12 14:19:45 +03:00
struct intel_scu_ipc_dev * scu = & ipcdev ;
2010-04-26 21:13:05 +04:00
u32 cmd = 0 ;
mutex_lock ( & ipclock ) ;
2015-10-12 14:19:46 +03:00
if ( scu - > dev = = NULL ) {
2010-07-19 12:37:42 +04:00
mutex_unlock ( & ipclock ) ;
return - ENODEV ;
}
2010-04-26 21:13:05 +04:00
cmd = ( addr > > 24 ) & 0xFF ;
if ( cmd = = IPC_I2C_READ ) {
2015-10-12 14:19:45 +03:00
writel ( addr , scu - > i2c_base + IPC_I2C_CNTRL_ADDR ) ;
2010-04-26 21:13:05 +04:00
/* Write not getting updated without delay */
mdelay ( 1 ) ;
2015-10-12 14:19:45 +03:00
* data = readl ( scu - > i2c_base + I2C_DATA_ADDR ) ;
2010-04-26 21:13:05 +04:00
} else if ( cmd = = IPC_I2C_WRITE ) {
2015-10-12 14:19:45 +03:00
writel ( * data , scu - > i2c_base + I2C_DATA_ADDR ) ;
2010-04-26 21:13:05 +04:00
mdelay ( 1 ) ;
2015-10-12 14:19:45 +03:00
writel ( addr , scu - > i2c_base + IPC_I2C_CNTRL_ADDR ) ;
2010-04-26 21:13:05 +04:00
} else {
2015-10-12 14:19:46 +03:00
dev_err ( scu - > dev ,
2010-04-26 21:13:05 +04:00
" intel_scu_ipc: I2C INVALID_CMD = 0x%x \n " , cmd ) ;
mutex_unlock ( & ipclock ) ;
2010-10-22 18:43:55 +04:00
return - EIO ;
2010-04-26 21:13:05 +04:00
}
mutex_unlock ( & ipclock ) ;
return 0 ;
}
EXPORT_SYMBOL ( intel_scu_ipc_i2c_cntrl ) ;
/*
* Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
* When ioc bit is set to 1 , caller api must wait for interrupt handler called
* which in turn unlocks the caller api . Currently this is not used
*
* This is edge triggered so we need take no action to clear anything
*/
static irqreturn_t ioc ( int irq , void * dev_id )
{
2015-10-12 14:19:45 +03:00
struct intel_scu_ipc_dev * scu = dev_id ;
if ( scu - > irq_mode )
complete ( & scu - > cmd_complete ) ;
2013-11-16 04:21:54 +04:00
2010-04-26 21:13:05 +04:00
return IRQ_HANDLED ;
}
/**
* ipc_probe - probe an Intel SCU IPC
2015-10-12 14:19:46 +03:00
* @ pdev : the PCI device matching
2010-04-26 21:13:05 +04:00
* @ id : entry in the match table
*
* Enable and install an intel SCU IPC . This appears in the PCI space
* but uses some hard coded addresses as well .
*/
2015-10-12 14:19:46 +03:00
static int ipc_probe ( struct pci_dev * pdev , const struct pci_device_id * id )
2010-04-26 21:13:05 +04:00
{
2013-12-03 04:20:00 +04:00
int err ;
2015-10-12 14:19:45 +03:00
struct intel_scu_ipc_dev * scu = & ipcdev ;
2013-11-15 02:15:04 +04:00
struct intel_scu_ipc_pdata_t * pdata ;
2010-04-26 21:13:05 +04:00
2015-10-12 14:19:46 +03:00
if ( scu - > dev ) /* We support only one SCU */
2010-04-26 21:13:05 +04:00
return - EBUSY ;
2013-12-03 04:20:00 +04:00
pdata = ( struct intel_scu_ipc_pdata_t * ) id - > driver_data ;
2017-04-05 19:05:24 +03:00
if ( ! pdata )
return - ENODEV ;
2013-11-15 02:15:04 +04:00
2015-10-12 14:19:45 +03:00
scu - > irq_mode = pdata - > irq_mode ;
2010-04-26 21:13:05 +04:00
2015-10-12 14:19:46 +03:00
err = pcim_enable_device ( pdev ) ;
2010-04-26 21:13:05 +04:00
if ( err )
return err ;
2015-10-12 14:19:46 +03:00
err = pcim_iomap_regions ( pdev , 1 < < 0 , pci_name ( pdev ) ) ;
2010-04-26 21:13:05 +04:00
if ( err )
return err ;
2015-10-12 14:19:45 +03:00
init_completion ( & scu - > cmd_complete ) ;
2013-11-16 04:21:54 +04:00
2015-10-12 14:19:46 +03:00
scu - > ipc_base = pcim_iomap_table ( pdev ) [ 0 ] ;
2010-04-26 21:13:05 +04:00
2015-10-12 14:19:45 +03:00
scu - > i2c_base = ioremap_nocache ( pdata - > i2c_base , pdata - > i2c_len ) ;
if ( ! scu - > i2c_base )
2010-04-26 21:13:05 +04:00
return - ENOMEM ;
2010-11-09 14:22:58 +03:00
2017-04-05 19:05:25 +03:00
err = devm_request_irq ( & pdev - > dev , pdev - > irq , ioc , 0 , " intel_scu_ipc " ,
scu ) ;
if ( err )
return err ;
/* Assign device at last */
scu - > dev = & pdev - > dev ;
2010-11-09 14:22:58 +03:00
intel_scu_devices_create ( ) ;
2015-10-12 14:19:46 +03:00
pci_set_drvdata ( pdev , scu ) ;
2010-04-26 21:13:05 +04:00
return 0 ;
}
2014-08-08 17:56:03 +04:00
static const struct pci_device_id pci_ids [ ] = {
2013-12-03 04:20:00 +04:00
{
2013-12-03 04:20:01 +04:00
PCI_VDEVICE ( INTEL , PCI_DEVICE_ID_LINCROFT ) ,
2013-12-03 04:20:00 +04:00
( kernel_ulong_t ) & intel_scu_ipc_lincroft_pdata ,
} , {
2013-12-03 04:20:01 +04:00
PCI_VDEVICE ( INTEL , PCI_DEVICE_ID_PENWELL ) ,
2013-12-03 04:20:00 +04:00
( kernel_ulong_t ) & intel_scu_ipc_penwell_pdata ,
} , {
2013-12-03 04:20:01 +04:00
PCI_VDEVICE ( INTEL , PCI_DEVICE_ID_CLOVERVIEW ) ,
2013-12-03 04:20:00 +04:00
( kernel_ulong_t ) & intel_scu_ipc_penwell_pdata ,
} , {
2013-12-03 04:20:01 +04:00
PCI_VDEVICE ( INTEL , PCI_DEVICE_ID_TANGIER ) ,
2013-12-03 04:20:00 +04:00
( kernel_ulong_t ) & intel_scu_ipc_tangier_pdata ,
} , {
0 ,
}
2010-04-26 21:13:05 +04:00
} ;
static struct pci_driver ipc_driver = {
2016-02-14 23:00:52 +03:00
. driver = {
. suppress_bind_attrs = true ,
} ,
2010-04-26 21:13:05 +04:00
. name = " intel_scu_ipc " ,
. id_table = pci_ids ,
. probe = ipc_probe ,
} ;
2016-02-14 23:00:52 +03:00
builtin_pci_driver ( ipc_driver ) ;