diff options
Diffstat (limited to 'drivers/platform/x86/intel_scu_ipc.c')
| -rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 190 | 
1 files changed, 59 insertions, 131 deletions
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 576c3ed9243..943f9084dcb 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -23,7 +23,7 @@  #include <linux/pm.h>  #include <linux/pci.h>  #include <linux/interrupt.h> -#include <asm/setup.h> +#include <asm/mrst.h>  #include <asm/intel_scu_ipc.h>  /* IPC defines the following message types */ @@ -38,10 +38,6 @@  #define IPC_CMD_PCNTRL_R      1 /* Register read */  #define IPC_CMD_PCNTRL_M      2 /* Register read-modify-write */ -/* Miscelaneous Command ids */ -#define IPC_CMD_INDIRECT_RD   2 /* 32bit indirect read */ -#define IPC_CMD_INDIRECT_WR   5 /* 32bit indirect write */ -  /*   * IPC register summary   * @@ -62,8 +58,8 @@  #define IPC_BASE_ADDR     0xFF11C000	/* IPC1 base register address */  #define IPC_MAX_ADDR      0x100		/* Maximum IPC regisers */ -#define IPC_WWBUF_SIZE    16		/* IPC Write buffer Size */ -#define IPC_RWBUF_SIZE    16		/* IPC Read buffer Size */ +#define IPC_WWBUF_SIZE    20		/* IPC Write buffer Size */ +#define IPC_RWBUF_SIZE    20		/* IPC Read buffer Size */  #define IPC_I2C_BASE      0xFF12B000	/* I2C control register base address */  #define IPC_I2C_MAX_ADDR  0x10		/* Maximum I2C regisers */ @@ -78,12 +74,7 @@ struct intel_scu_ipc_dev {  static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */ -static int platform = 1; -module_param(platform, int, 0); -MODULE_PARM_DESC(platform, "1 for moorestown platform"); - - - +static int platform;		/* Platform type */  /*   * IPC Read Buffer (Read Only): @@ -119,24 +110,6 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */  }  /* - * IPC destination Pointer (Write Only): - * Use content as pointer for destination write - */ -static inline void ipc_write_dptr(u32 data) /* Write dptr data */ -{ -	writel(data, ipcdev.ipc_base + 0x0C); -} - -/* - * IPC Source Pointer (Write Only): - * Use content as pointer for read location -*/ -static inline void ipc_write_sptr(u32 data) /* Write dptr data */ -{ -	writel(data, ipcdev.ipc_base + 0x08); -} - -/*   * 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 @@ -154,7 +127,7 @@ static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */  	return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);  } -static inline u8 ipc_data_readl(u32 offset) /* Read ipc u32 data */ +static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */  {  	return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);  } @@ -175,62 +148,73 @@ static inline int busy_loop(void) /* Wait till scu status is busy */  			return -ETIMEDOUT;  		}  	} -	return (status >> 1) & 1; +	if ((status >> 1) & 1) +		return -EIO; + +	return 0;  }  /* 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)  { -	int nc; +	int i, nc, bytes, d;  	u32 offset = 0;  	u32 err = 0; -	u8 cbuf[IPC_WWBUF_SIZE] = { '\0' }; +	u8 cbuf[IPC_WWBUF_SIZE] = { };  	u32 *wbuf = (u32 *)&cbuf;  	mutex_lock(&ipclock); + +	memset(cbuf, 0, sizeof(cbuf)); +  	if (ipcdev.pdev == NULL) {  		mutex_unlock(&ipclock);  		return -ENODEV;  	} -	if (platform == 1) { -		/* Entry is 4 bytes for read/write, 5 bytes for read modify */ -		for (nc = 0; nc < count; nc++) { +	if (platform != MRST_CPU_CHIP_PENWELL) { +		bytes = 0; +		d = 0; +		for (i = 0; i < count; i++) { +			cbuf[bytes++] = addr[i]; +			cbuf[bytes++] = addr[i] >> 8; +			if (id != IPC_CMD_PCNTRL_R) +				cbuf[bytes++] = data[d++]; +			if (id == IPC_CMD_PCNTRL_M) +				cbuf[bytes++] = data[d++]; +		} +		for (i = 0; i < bytes; i += 4) +			ipc_data_writel(wbuf[i/4], i); +		ipc_command(bytes << 16 |  id << 12 | 0 << 8 | op); +	} else { +		for (nc = 0; nc < count; nc++, offset += 2) {  			cbuf[offset] = addr[nc];  			cbuf[offset + 1] = addr[nc] >> 8; -			if (id != IPC_CMD_PCNTRL_R) -				cbuf[offset + 2] = data[nc]; -			if (id == IPC_CMD_PCNTRL_M) { -				cbuf[offset + 3] = data[nc + 1]; -				offset += 1; -			} -			offset += 3;  		} -		for (nc = 0, offset = 0; nc < count; nc++, offset += 4) -			ipc_data_writel(wbuf[nc], offset); /* Write wbuff */ -	} else { -		for (nc = 0, offset = 0; nc < count; nc++, offset += 2) -			ipc_data_writel(addr[nc], offset); /* Write addresses */ -		if (id != IPC_CMD_PCNTRL_R) { -			for (nc = 0; nc < count; nc++, offset++) -				ipc_data_writel(data[nc], offset); /* Write data */ -			if (id == IPC_CMD_PCNTRL_M) -				ipc_data_writel(data[nc + 1], offset); /* Mask value*/ +		if (id == IPC_CMD_PCNTRL_R) { +			for (nc = 0, offset = 0; nc < count; nc++, offset += 4) +				ipc_data_writel(wbuf[nc], offset); +			ipc_command((count*2) << 16 |  id << 12 | 0 << 8 | op); +		} 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) +				ipc_data_writel(wbuf[nc], offset); +			ipc_command((count*3) << 16 |  id << 12 | 0 << 8 | op); +		} else if (id == IPC_CMD_PCNTRL_M) { +			cbuf[offset] = data[0]; +			cbuf[offset + 1] = data[1]; +			ipc_data_writel(wbuf[0], 0); /* Write wbuff */ +			ipc_command(4 << 16 |  id << 12 | 0 << 8 | op);  		}  	} -	if (id != IPC_CMD_PCNTRL_M) -		ipc_command((count * 3) << 16 |  id << 12 | 0 << 8 | op); -	else -		ipc_command((count * 4) << 16 |  id << 12 | 0 << 8 | op); -  	err = busy_loop(); -  	if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */  		/* Workaround: values are read as 0 without memcpy_fromio */ -		memcpy_fromio(cbuf, ipcdev.ipc_base + IPC_READ_BUFFER, 16); -		if (platform == 1) { +		memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); +		if (platform != MRST_CPU_CHIP_PENWELL) {  			for (nc = 0, offset = 2; nc < count; nc++, offset += 3)  				data[nc] = ipc_data_readb(offset);  		} else { @@ -405,70 +389,6 @@ int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)  EXPORT_SYMBOL(intel_scu_ipc_update_register);  /** - *	intel_scu_ipc_register_read	-	32bit indirect read - *	@addr: register address - *	@value: 32bit value return - * - *	Performs IA 32 bit indirect read, returns 0 on success, or an - *	error code. - * - *	Can be used when SCCB(System Controller Configuration Block) register - *	HRIM(Honor Restricted IPC Messages) is set (bit 23) - * - *	This function may sleep. Locking for SCU accesses is handled for - *	the caller. - */ -int intel_scu_ipc_register_read(u32 addr, u32 *value) -{ -	u32 err = 0; - -	mutex_lock(&ipclock); -	if (ipcdev.pdev == NULL) { -		mutex_unlock(&ipclock); -		return -ENODEV; -	} -	ipc_write_sptr(addr); -	ipc_command(4 << 16 | IPC_CMD_INDIRECT_RD); -	err = busy_loop(); -	*value = ipc_data_readl(0); -	mutex_unlock(&ipclock); -	return err; -} -EXPORT_SYMBOL(intel_scu_ipc_register_read); - -/** - *	intel_scu_ipc_register_write	-	32bit indirect write - *	@addr: register address - *	@value: 32bit value to write - * - *	Performs IA 32 bit indirect write, returns 0 on success, or an - *	error code. - * - *	Can be used when SCCB(System Controller Configuration Block) register - *	HRIM(Honor Restricted IPC Messages) is set (bit 23) - * - *	This function may sleep. Locking for SCU accesses is handled for - *	the caller. - */ -int intel_scu_ipc_register_write(u32 addr, u32 value) -{ -	u32 err = 0; - -	mutex_lock(&ipclock); -	if (ipcdev.pdev == NULL) { -		mutex_unlock(&ipclock); -		return -ENODEV; -	} -	ipc_write_dptr(addr); -	ipc_data_writel(value, 0); -	ipc_command(4 << 16 | IPC_CMD_INDIRECT_WR); -	err = busy_loop(); -	mutex_unlock(&ipclock); -	return err; -} -EXPORT_SYMBOL(intel_scu_ipc_register_write); - -/**   *	intel_scu_ipc_simple_command	-	send a simple command   *	@cmd: command   *	@sub: sub type @@ -489,7 +409,7 @@ int intel_scu_ipc_simple_command(int cmd, int sub)  		mutex_unlock(&ipclock);  		return -ENODEV;  	} -	ipc_command(cmd << 12 | sub); +	ipc_command(sub << 12 | cmd);  	err = busy_loop();  	mutex_unlock(&ipclock);  	return err; @@ -501,9 +421,9 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command);   *	@cmd: command   *	@sub: sub type   *	@in: input data - *	@inlen: input length + *	@inlen: input length in dwords   *	@out: output data - *	@outlein: output length + *	@outlein: output length in dwords   *   *	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 @@ -524,7 +444,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,  	for (i = 0; i < inlen; i++)  		ipc_data_writel(*in++, 4 * i); -	ipc_command(cmd << 12 | sub); +	ipc_command((inlen << 16) | (sub << 12) | cmd);  	err = busy_loop();  	for (i = 0; i < outlen; i++) @@ -556,6 +476,10 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)  	u32 cmd = 0;  	mutex_lock(&ipclock); +	if (ipcdev.pdev == NULL) { +		mutex_unlock(&ipclock); +		return -ENODEV; +	}  	cmd = (addr >> 24) & 0xFF;  	if (cmd == IPC_I2C_READ) {  		writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); @@ -799,6 +723,7 @@ static void ipc_remove(struct pci_dev *pdev)  static const struct pci_device_id pci_ids[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)}, +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},  	{ 0,}  };  MODULE_DEVICE_TABLE(pci, pci_ids); @@ -813,6 +738,9 @@ static struct pci_driver ipc_driver = {  static int __init intel_scu_ipc_init(void)  { +	platform = mrst_identify_cpu(); +	if (platform == 0) +		return -ENODEV;  	return  pci_register_driver(&ipc_driver);  }  |