99#include <linux/errno.h>
1010#include <linux/interrupt.h>
1111#include <linux/io.h>
12+ #include <linux/irq.h>
1213#include <linux/mfd/syscon.h>
1314#include <linux/module.h>
1415#include <linux/of.h>
2829
2930#define KCS_CHANNEL_MAX 4
3031
32+ /*
33+ * Field class descriptions
34+ *
35+ * LPCyE Enable LPC channel y
36+ * IBFIEy Input Buffer Full IRQ Enable for LPC channel y
37+ * IRQxEy Assert SerIRQ x for LPC channel y (Deprecated, use IDyIRQX, IRQXEy)
38+ * IDyIRQX Use the specified 4-bit SerIRQ for LPC channel y
39+ * SELyIRQX SerIRQ polarity for LPC channel y (low: 0, high: 1)
40+ * IRQXEy Assert the SerIRQ specified in IDyIRQX for LPC channel y
41+ */
42+
43+ #define LPC_TYIRQX_LOW 0b00
44+ #define LPC_TYIRQX_HIGH 0b01
45+ #define LPC_TYIRQX_RSVD 0b10
46+ #define LPC_TYIRQX_RISING 0b11
47+
3148#define LPC_HICR0 0x000
3249#define LPC_HICR0_LPC3E BIT(7)
3350#define LPC_HICR0_LPC2E BIT(6)
3956#define LPC_HICR4 0x010
4057#define LPC_HICR4_LADR12AS BIT(7)
4158#define LPC_HICR4_KCSENBL BIT(2)
59+ #define LPC_SIRQCR0 0x070
60+ /* IRQ{12,1}E1 are deprecated as of AST2600 A3 but necessary for prior chips */
61+ #define LPC_SIRQCR0_IRQ12E1 BIT(1)
62+ #define LPC_SIRQCR0_IRQ1E1 BIT(0)
63+ #define LPC_HICR5 0x080
64+ #define LPC_HICR5_ID3IRQX_MASK GENMASK(23, 20)
65+ #define LPC_HICR5_ID3IRQX_SHIFT 20
66+ #define LPC_HICR5_ID2IRQX_MASK GENMASK(19, 16)
67+ #define LPC_HICR5_ID2IRQX_SHIFT 16
68+ #define LPC_HICR5_SEL3IRQX BIT(15)
69+ #define LPC_HICR5_IRQXE3 BIT(14)
70+ #define LPC_HICR5_SEL2IRQX BIT(13)
71+ #define LPC_HICR5_IRQXE2 BIT(12)
4272#define LPC_LADR3H 0x014
4373#define LPC_LADR3L 0x018
4474#define LPC_LADR12H 0x01C
5585#define LPC_HICRB 0x100
5686#define LPC_HICRB_IBFIF4 BIT(1)
5787#define LPC_HICRB_LPC4E BIT(0)
88+ #define LPC_HICRC 0x104
89+ #define LPC_HICRC_ID4IRQX_MASK GENMASK(7, 4)
90+ #define LPC_HICRC_ID4IRQX_SHIFT 4
91+ #define LPC_HICRC_TY4IRQX_MASK GENMASK(3, 2)
92+ #define LPC_HICRC_TY4IRQX_SHIFT 2
93+ #define LPC_HICRC_OBF4_AUTO_CLR BIT(1)
94+ #define LPC_HICRC_IRQXE4 BIT(0)
5895#define LPC_LADR4 0x110
5996#define LPC_IDR4 0x114
6097#define LPC_ODR4 0x118
6198#define LPC_STR4 0x11C
6299
63100#define OBE_POLL_PERIOD (HZ / 2)
64101
102+ enum aspeed_kcs_irq_mode {
103+ aspeed_kcs_irq_none ,
104+ aspeed_kcs_irq_serirq ,
105+ };
106+
65107struct aspeed_kcs_bmc {
66108 struct kcs_bmc_device kcs_bmc ;
67109
68110 struct regmap * map ;
69111
112+ struct {
113+ enum aspeed_kcs_irq_mode mode ;
114+ int id ;
115+ } upstream_irq ;
116+
70117 struct {
71118 spinlock_t lock ;
72119 bool remove ;
@@ -103,6 +150,49 @@ static void aspeed_kcs_outb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 data)
103150
104151 rc = regmap_write (priv -> map , reg , data );
105152 WARN (rc != 0 , "regmap_write() failed: %d\n" , rc );
153+
154+ /* Trigger the upstream IRQ on ODR writes, if enabled */
155+
156+ switch (reg ) {
157+ case LPC_ODR1 :
158+ case LPC_ODR2 :
159+ case LPC_ODR3 :
160+ case LPC_ODR4 :
161+ break ;
162+ default :
163+ return ;
164+ }
165+
166+ if (priv -> upstream_irq .mode != aspeed_kcs_irq_serirq )
167+ return ;
168+
169+ switch (kcs_bmc -> channel ) {
170+ case 1 :
171+ switch (priv -> upstream_irq .id ) {
172+ case 12 :
173+ regmap_update_bits (priv -> map , LPC_SIRQCR0 , LPC_SIRQCR0_IRQ12E1 ,
174+ LPC_SIRQCR0_IRQ12E1 );
175+ break ;
176+ case 1 :
177+ regmap_update_bits (priv -> map , LPC_SIRQCR0 , LPC_SIRQCR0_IRQ1E1 ,
178+ LPC_SIRQCR0_IRQ1E1 );
179+ break ;
180+ default :
181+ break ;
182+ }
183+ break ;
184+ case 2 :
185+ regmap_update_bits (priv -> map , LPC_HICR5 , LPC_HICR5_IRQXE2 , LPC_HICR5_IRQXE2 );
186+ break ;
187+ case 3 :
188+ regmap_update_bits (priv -> map , LPC_HICR5 , LPC_HICR5_IRQXE3 , LPC_HICR5_IRQXE3 );
189+ break ;
190+ case 4 :
191+ regmap_update_bits (priv -> map , LPC_HICRC , LPC_HICRC_IRQXE4 , LPC_HICRC_IRQXE4 );
192+ break ;
193+ default :
194+ break ;
195+ }
106196}
107197
108198static void aspeed_kcs_updateb (struct kcs_bmc_device * kcs_bmc , u32 reg , u8 mask , u8 val )
@@ -161,6 +251,73 @@ static void aspeed_kcs_set_address(struct kcs_bmc_device *kcs_bmc, u16 addr)
161251 }
162252}
163253
254+ static inline int aspeed_kcs_map_serirq_type (u32 dt_type )
255+ {
256+ switch (dt_type ) {
257+ case IRQ_TYPE_EDGE_RISING :
258+ return LPC_TYIRQX_RISING ;
259+ case IRQ_TYPE_LEVEL_HIGH :
260+ return LPC_TYIRQX_HIGH ;
261+ case IRQ_TYPE_LEVEL_LOW :
262+ return LPC_TYIRQX_LOW ;
263+ default :
264+ return - EINVAL ;
265+ }
266+ }
267+
268+ static int aspeed_kcs_config_upstream_irq (struct aspeed_kcs_bmc * priv , u32 id , u32 dt_type )
269+ {
270+ unsigned int mask , val , hw_type ;
271+
272+ if (id > 15 )
273+ return - EINVAL ;
274+
275+ hw_type = aspeed_kcs_map_serirq_type (dt_type );
276+ if (hw_type < 0 )
277+ return hw_type ;
278+
279+ priv -> upstream_irq .mode = aspeed_kcs_irq_serirq ;
280+ priv -> upstream_irq .id = id ;
281+
282+ switch (priv -> kcs_bmc .channel ) {
283+ case 1 :
284+ /* Needs IRQxE1 rather than (ID1IRQX, SEL1IRQX, IRQXE1) before AST2600 A3 */
285+ break ;
286+ case 2 :
287+ if (!(hw_type == LPC_TYIRQX_LOW || hw_type == LPC_TYIRQX_HIGH ))
288+ return - EINVAL ;
289+
290+ mask = LPC_HICR5_SEL2IRQX | LPC_HICR5_ID2IRQX_MASK ;
291+ val = (id << LPC_HICR5_ID2IRQX_SHIFT );
292+ val |= (hw_type == LPC_TYIRQX_HIGH ) ? LPC_HICR5_SEL2IRQX : 0 ;
293+ regmap_update_bits (priv -> map , LPC_HICR5 , mask , val );
294+
295+ break ;
296+ case 3 :
297+ if (!(hw_type == LPC_TYIRQX_LOW || hw_type == LPC_TYIRQX_HIGH ))
298+ return - EINVAL ;
299+
300+ mask = LPC_HICR5_SEL3IRQX | LPC_HICR5_ID3IRQX_MASK ;
301+ val = (id << LPC_HICR5_ID3IRQX_SHIFT );
302+ val |= (hw_type == LPC_TYIRQX_HIGH ) ? LPC_HICR5_SEL3IRQX : 0 ;
303+ regmap_update_bits (priv -> map , LPC_HICR5 , mask , val );
304+
305+ break ;
306+ case 4 :
307+ mask = LPC_HICRC_ID4IRQX_MASK | LPC_HICRC_TY4IRQX_MASK | LPC_HICRC_OBF4_AUTO_CLR ;
308+ val = (id << LPC_HICRC_ID4IRQX_SHIFT ) | (hw_type << LPC_HICRC_TY4IRQX_SHIFT );
309+ regmap_update_bits (priv -> map , LPC_HICRC , mask , val );
310+ break ;
311+ default :
312+ dev_warn (priv -> kcs_bmc .dev ,
313+ "SerIRQ configuration not supported on KCS channel %d\n" ,
314+ priv -> kcs_bmc .channel );
315+ return - EINVAL ;
316+ }
317+
318+ return 0 ;
319+ }
320+
164321static void aspeed_kcs_enable_channel (struct kcs_bmc_device * kcs_bmc , bool enable )
165322{
166323 struct aspeed_kcs_bmc * priv = to_aspeed_kcs_bmc (kcs_bmc );
@@ -262,7 +419,7 @@ static irqreturn_t aspeed_kcs_irq(int irq, void *arg)
262419 return kcs_bmc_handle_event (kcs_bmc );
263420}
264421
265- static int aspeed_kcs_config_irq (struct kcs_bmc_device * kcs_bmc ,
422+ static int aspeed_kcs_config_downstream_irq (struct kcs_bmc_device * kcs_bmc ,
266423 struct platform_device * pdev )
267424{
268425 struct device * dev = & pdev -> dev ;
@@ -368,6 +525,8 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
368525 struct aspeed_kcs_bmc * priv ;
369526 struct device_node * np ;
370527 int rc , channel , addr ;
528+ bool have_upstream_irq ;
529+ u32 upstream_irq [2 ];
371530
372531 np = pdev -> dev .of_node -> parent ;
373532 if (!of_device_is_compatible (np , "aspeed,ast2400-lpc-v2" ) &&
@@ -376,6 +535,7 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
376535 dev_err (& pdev -> dev , "unsupported LPC device binding\n" );
377536 return - ENODEV ;
378537 }
538+
379539 ops = of_device_get_match_data (& pdev -> dev );
380540 if (!ops )
381541 return - EINVAL ;
@@ -388,6 +548,13 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
388548 if (addr < 0 )
389549 return addr ;
390550
551+ np = pdev -> dev .of_node ;
552+ rc = of_property_read_u32_array (np , "aspeed,lpc-interrupts" , upstream_irq , 2 );
553+ if (rc && rc != - EINVAL )
554+ return - EINVAL ;
555+
556+ have_upstream_irq = !rc ;
557+
391558 priv = devm_kzalloc (& pdev -> dev , sizeof (* priv ), GFP_KERNEL );
392559 if (!priv )
393560 return - ENOMEM ;
@@ -410,10 +577,20 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
410577
411578 aspeed_kcs_set_address (kcs_bmc , addr );
412579
413- rc = aspeed_kcs_config_irq (kcs_bmc , pdev );
580+ /* Host to BMC IRQ */
581+ rc = aspeed_kcs_config_downstream_irq (kcs_bmc , pdev );
414582 if (rc )
415583 return rc ;
416584
585+ /* BMC to Host IRQ */
586+ if (have_upstream_irq ) {
587+ rc = aspeed_kcs_config_upstream_irq (priv , upstream_irq [0 ], upstream_irq [1 ]);
588+ if (rc < 0 )
589+ return rc ;
590+ } else {
591+ priv -> upstream_irq .mode = aspeed_kcs_irq_none ;
592+ }
593+
417594 platform_set_drvdata (pdev , priv );
418595
419596 aspeed_kcs_irq_mask_update (kcs_bmc , (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE ), 0 );
@@ -480,4 +657,5 @@ module_platform_driver(ast_kcs_bmc_driver);
480657
481658MODULE_LICENSE ("GPL v2" );
482659MODULE_AUTHOR ("Haiyue Wang <haiyue.wang@linux.intel.com>" );
660+ MODULE_AUTHOR ("Andrew Jeffery <andrew@aj.id.au>" );
483661MODULE_DESCRIPTION ("Aspeed device interface to the KCS BMC device" );
0 commit comments