99 * Sanket Goswami <Sanket.Goswami@amd.com>
1010 */
1111
12+ #include <linux/bitops.h>
1213#include <linux/device.h>
1314#include <linux/errno.h>
1415#include <linux/gfp_types.h>
2223
2324#include "i2c-piix4.h"
2425
26+ /* ASF register bits */
27+ #define ASF_SLV_LISTN 0
28+ #define ASF_SLV_INTR 1
29+ #define ASF_SLV_RST 4
30+ #define ASF_PEC_SP 5
31+ #define ASF_DATA_EN 7
32+ #define ASF_MSTR_EN 16
33+ #define ASF_CLK_EN 17
34+
35+ /* ASF address offsets */
36+ #define ASFLISADDR (0x09 + piix4_smba)
37+ #define ASFSTA (0x0A + piix4_smba)
38+ #define ASFSLVSTA (0x0D + piix4_smba)
39+ #define ASFDATABNKSEL (0x13 + piix4_smba)
40+ #define ASFSLVEN (0x15 + piix4_smba)
41+
42+ #define ASF_BLOCK_MAX_BYTES 72
43+
2544struct amd_asf_dev {
2645 struct i2c_adapter adap ;
46+ struct i2c_client * target ;
2747 struct sb800_mmio_cfg mmio_cfg ;
2848 struct resource * port_addr ;
2949};
3050
51+ static void amd_asf_update_ioport_target (unsigned short piix4_smba , u8 bit ,
52+ unsigned long offset , bool set )
53+ {
54+ unsigned long reg ;
55+
56+ reg = inb_p (offset );
57+ __assign_bit (bit , & reg , set );
58+ outb_p (reg , offset );
59+ }
60+
61+ static void amd_asf_update_mmio_target (struct amd_asf_dev * dev , u8 bit , bool set )
62+ {
63+ unsigned long reg ;
64+
65+ reg = ioread32 (dev -> mmio_cfg .addr );
66+ __assign_bit (bit , & reg , set );
67+ iowrite32 (reg , dev -> mmio_cfg .addr );
68+ }
69+
70+ static void amd_asf_setup_target (struct amd_asf_dev * dev )
71+ {
72+ unsigned short piix4_smba = dev -> port_addr -> start ;
73+
74+ /* Reset both host and target before setting up */
75+ outb_p (0 , SMBHSTSTS );
76+ outb_p (0 , ASFSLVSTA );
77+ outb_p (0 , ASFSTA );
78+
79+ /* Update target address */
80+ amd_asf_update_ioport_target (piix4_smba , ASF_SLV_LISTN , ASFLISADDR , true);
81+ /* Enable target and set the clock */
82+ amd_asf_update_mmio_target (dev , ASF_MSTR_EN , false);
83+ amd_asf_update_mmio_target (dev , ASF_CLK_EN , true);
84+ /* Enable target interrupt */
85+ amd_asf_update_ioport_target (piix4_smba , ASF_SLV_INTR , ASFSLVEN , true);
86+ amd_asf_update_ioport_target (piix4_smba , ASF_SLV_RST , ASFSLVEN , false);
87+ /* Enable PEC and PEC append */
88+ amd_asf_update_ioport_target (piix4_smba , ASF_DATA_EN , SMBHSTCNT , true);
89+ amd_asf_update_ioport_target (piix4_smba , ASF_PEC_SP , SMBHSTCNT , true);
90+ }
91+
92+ static int amd_asf_access (struct i2c_adapter * adap , u16 addr , u8 command , u8 * data )
93+ {
94+ struct amd_asf_dev * dev = i2c_get_adapdata (adap );
95+ unsigned short piix4_smba = dev -> port_addr -> start ;
96+ u8 i , len ;
97+
98+ outb_p ((addr << 1 ), SMBHSTADD );
99+ outb_p (command , SMBHSTCMD );
100+ len = data [0 ];
101+ if (len == 0 || len > ASF_BLOCK_MAX_BYTES )
102+ return - EINVAL ;
103+
104+ outb_p (len , SMBHSTDAT0 );
105+ /* Reset SMBBLKDAT */
106+ inb_p (SMBHSTCNT );
107+ for (i = 1 ; i <= len ; i ++ )
108+ outb_p (data [i ], SMBBLKDAT );
109+
110+ outb_p (PIIX4_BLOCK_DATA , SMBHSTCNT );
111+ /* Enable PEC and PEC append */
112+ amd_asf_update_ioport_target (piix4_smba , ASF_DATA_EN , SMBHSTCNT , true);
113+ amd_asf_update_ioport_target (piix4_smba , ASF_PEC_SP , SMBHSTCNT , true);
114+
115+ return piix4_transaction (adap , piix4_smba );
116+ }
117+
118+ static int amd_asf_xfer (struct i2c_adapter * adap , struct i2c_msg * msgs , int num )
119+ {
120+ struct amd_asf_dev * dev = i2c_get_adapdata (adap );
121+ unsigned short piix4_smba = dev -> port_addr -> start ;
122+ u8 asf_data [ASF_BLOCK_MAX_BYTES ];
123+ struct i2c_msg * dev_msgs = msgs ;
124+ u8 prev_port ;
125+ int ret ;
126+
127+ if (msgs -> flags & I2C_M_RD ) {
128+ dev_err (& adap -> dev , "ASF: Read not supported\n" );
129+ return - EOPNOTSUPP ;
130+ }
131+
132+ /* Exclude the receive header and PEC */
133+ if (msgs -> len > ASF_BLOCK_MAX_BYTES - 3 ) {
134+ dev_warn (& adap -> dev , "ASF: max message length exceeded\n" );
135+ return - EOPNOTSUPP ;
136+ }
137+
138+ asf_data [0 ] = dev_msgs -> len ;
139+ memcpy (asf_data + 1 , dev_msgs [0 ].buf , dev_msgs -> len );
140+
141+ ret = piix4_sb800_region_request (& adap -> dev , & dev -> mmio_cfg );
142+ if (ret )
143+ return ret ;
144+
145+ amd_asf_update_ioport_target (piix4_smba , ASF_SLV_RST , ASFSLVEN , true);
146+ amd_asf_update_ioport_target (piix4_smba , ASF_SLV_LISTN , ASFLISADDR , false);
147+ /* Clear ASF target status */
148+ outb_p (0 , ASFSLVSTA );
149+
150+ /* Enable ASF SMBus controller function */
151+ amd_asf_update_mmio_target (dev , ASF_MSTR_EN , true);
152+ prev_port = piix4_sb800_port_sel (0 , & dev -> mmio_cfg );
153+ ret = amd_asf_access (adap , msgs -> addr , msgs [0 ].buf [0 ], asf_data );
154+ piix4_sb800_port_sel (prev_port , & dev -> mmio_cfg );
155+ amd_asf_setup_target (dev );
156+ piix4_sb800_region_release (& adap -> dev , & dev -> mmio_cfg );
157+ return ret ;
158+ }
159+
160+ static int amd_asf_reg_target (struct i2c_client * target )
161+ {
162+ struct amd_asf_dev * dev = i2c_get_adapdata (target -> adapter );
163+ unsigned short piix4_smba = dev -> port_addr -> start ;
164+ int ret ;
165+ u8 reg ;
166+
167+ if (dev -> target )
168+ return - EBUSY ;
169+
170+ ret = piix4_sb800_region_request (& target -> dev , & dev -> mmio_cfg );
171+ if (ret )
172+ return ret ;
173+
174+ reg = (target -> addr << 1 ) | I2C_M_RD ;
175+ outb_p (reg , ASFLISADDR );
176+
177+ amd_asf_setup_target (dev );
178+ dev -> target = target ;
179+ amd_asf_update_ioport_target (piix4_smba , ASF_DATA_EN , ASFDATABNKSEL , false);
180+ piix4_sb800_region_release (& target -> dev , & dev -> mmio_cfg );
181+
182+ return 0 ;
183+ }
184+
185+ static int amd_asf_unreg_target (struct i2c_client * target )
186+ {
187+ struct amd_asf_dev * dev = i2c_get_adapdata (target -> adapter );
188+ unsigned short piix4_smba = dev -> port_addr -> start ;
189+
190+ amd_asf_update_ioport_target (piix4_smba , ASF_SLV_INTR , ASFSLVEN , false);
191+ amd_asf_update_ioport_target (piix4_smba , ASF_SLV_RST , ASFSLVEN , true);
192+ dev -> target = NULL ;
193+
194+ return 0 ;
195+ }
196+
197+ static u32 amd_asf_func (struct i2c_adapter * adapter )
198+ {
199+ return I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
200+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_PEC | I2C_FUNC_SLAVE ;
201+ }
202+
203+ static const struct i2c_algorithm amd_asf_smbus_algorithm = {
204+ .master_xfer = amd_asf_xfer ,
205+ .reg_slave = amd_asf_reg_target ,
206+ .unreg_slave = amd_asf_unreg_target ,
207+ .functionality = amd_asf_func ,
208+ };
209+
31210static int amd_asf_probe (struct platform_device * pdev )
32211{
33212 struct device * dev = & pdev -> dev ;
@@ -43,6 +222,7 @@ static int amd_asf_probe(struct platform_device *pdev)
43222 return dev_err_probe (dev , - EINVAL , "missing IO resources\n" );
44223
45224 asf_dev -> adap .owner = THIS_MODULE ;
225+ asf_dev -> adap .algo = & amd_asf_smbus_algorithm ;
46226 asf_dev -> adap .dev .parent = dev ;
47227
48228 i2c_set_adapdata (& asf_dev -> adap , asf_dev );
@@ -66,5 +246,6 @@ static struct platform_driver amd_asf_driver = {
66246};
67247module_platform_driver (amd_asf_driver );
68248
249+ MODULE_IMPORT_NS (PIIX4_SMBUS );
69250MODULE_LICENSE ("GPL" );
70251MODULE_DESCRIPTION ("AMD Alert Standard Format Driver" );
0 commit comments