Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2013 TangoTec Ltd.
0004  * Author: Baruch Siach <baruch@tkos.co.il>
0005  *
0006  * Driver for the Xtensa LX4 GPIO32 Option
0007  *
0008  * Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22
0009  *
0010  * GPIO32 is a standard optional extension to the Xtensa architecture core that
0011  * provides preconfigured output and input ports for intra SoC signaling. The
0012  * GPIO32 option is implemented as 32bit Tensilica Instruction Extension (TIE)
0013  * output state called EXPSTATE, and 32bit input wire called IMPWIRE. This
0014  * driver treats input and output states as two distinct devices.
0015  *
0016  * Access to GPIO32 specific instructions is controlled by the CPENABLE
0017  * (Coprocessor Enable Bits) register. By default Xtensa Linux startup code
0018  * disables access to all coprocessors. This driver sets the CPENABLE bit
0019  * corresponding to GPIO32 before any GPIO32 specific instruction, and restores
0020  * CPENABLE state after that.
0021  *
0022  * This driver is currently incompatible with SMP. The GPIO32 extension is not
0023  * guaranteed to be available in all cores. Moreover, each core controls a
0024  * different set of IO wires. A theoretical SMP aware version of this driver
0025  * would need to have a per core workqueue to do the actual GPIO manipulation.
0026  */
0027 
0028 #include <linux/err.h>
0029 #include <linux/module.h>
0030 #include <linux/gpio/driver.h>
0031 #include <linux/bitops.h>
0032 #include <linux/platform_device.h>
0033 
0034 #include <asm/coprocessor.h> /* CPENABLE read/write macros */
0035 
0036 #ifndef XCHAL_CP_ID_XTIOP
0037 #error GPIO32 option is not enabled for your xtensa core variant
0038 #endif
0039 
0040 #if XCHAL_HAVE_CP
0041 
0042 static inline unsigned long enable_cp(unsigned long *cpenable)
0043 {
0044     unsigned long flags;
0045 
0046     local_irq_save(flags);
0047     *cpenable = xtensa_get_sr(cpenable);
0048     xtensa_set_sr(*cpenable | BIT(XCHAL_CP_ID_XTIOP), cpenable);
0049     return flags;
0050 }
0051 
0052 static inline void disable_cp(unsigned long flags, unsigned long cpenable)
0053 {
0054     xtensa_set_sr(cpenable, cpenable);
0055     local_irq_restore(flags);
0056 }
0057 
0058 #else
0059 
0060 static inline unsigned long enable_cp(unsigned long *cpenable)
0061 {
0062     *cpenable = 0; /* avoid uninitialized value warning */
0063     return 0;
0064 }
0065 
0066 static inline void disable_cp(unsigned long flags, unsigned long cpenable)
0067 {
0068 }
0069 
0070 #endif /* XCHAL_HAVE_CP */
0071 
0072 static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset)
0073 {
0074     return GPIO_LINE_DIRECTION_IN; /* input only */
0075 }
0076 
0077 static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset)
0078 {
0079     unsigned long flags, saved_cpenable;
0080     u32 impwire;
0081 
0082     flags = enable_cp(&saved_cpenable);
0083     __asm__ __volatile__("read_impwire %0" : "=a" (impwire));
0084     disable_cp(flags, saved_cpenable);
0085 
0086     return !!(impwire & BIT(offset));
0087 }
0088 
0089 static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset,
0090                     int value)
0091 {
0092     BUG(); /* output only; should never be called */
0093 }
0094 
0095 static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset)
0096 {
0097     return GPIO_LINE_DIRECTION_OUT; /* output only */
0098 }
0099 
0100 static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset)
0101 {
0102     unsigned long flags, saved_cpenable;
0103     u32 expstate;
0104 
0105     flags = enable_cp(&saved_cpenable);
0106     __asm__ __volatile__("rur.expstate %0" : "=a" (expstate));
0107     disable_cp(flags, saved_cpenable);
0108 
0109     return !!(expstate & BIT(offset));
0110 }
0111 
0112 static void xtensa_expstate_set_value(struct gpio_chip *gc, unsigned offset,
0113                      int value)
0114 {
0115     unsigned long flags, saved_cpenable;
0116     u32 mask = BIT(offset);
0117     u32 val = value ? BIT(offset) : 0;
0118 
0119     flags = enable_cp(&saved_cpenable);
0120     __asm__ __volatile__("wrmsk_expstate %0, %1"
0121                  :: "a" (val), "a" (mask));
0122     disable_cp(flags, saved_cpenable);
0123 }
0124 
0125 static struct gpio_chip impwire_chip = {
0126     .label      = "impwire",
0127     .base       = -1,
0128     .ngpio      = 32,
0129     .get_direction  = xtensa_impwire_get_direction,
0130     .get        = xtensa_impwire_get_value,
0131     .set        = xtensa_impwire_set_value,
0132 };
0133 
0134 static struct gpio_chip expstate_chip = {
0135     .label      = "expstate",
0136     .base       = -1,
0137     .ngpio      = 32,
0138     .get_direction  = xtensa_expstate_get_direction,
0139     .get        = xtensa_expstate_get_value,
0140     .set        = xtensa_expstate_set_value,
0141 };
0142 
0143 static int xtensa_gpio_probe(struct platform_device *pdev)
0144 {
0145     int ret;
0146 
0147     ret = gpiochip_add_data(&impwire_chip, NULL);
0148     if (ret)
0149         return ret;
0150     return gpiochip_add_data(&expstate_chip, NULL);
0151 }
0152 
0153 static struct platform_driver xtensa_gpio_driver = {
0154     .driver     = {
0155         .name       = "xtensa-gpio",
0156     },
0157     .probe      = xtensa_gpio_probe,
0158 };
0159 
0160 static int __init xtensa_gpio_init(void)
0161 {
0162     struct platform_device *pdev;
0163 
0164     pdev = platform_device_register_simple("xtensa-gpio", 0, NULL, 0);
0165     if (IS_ERR(pdev))
0166         return PTR_ERR(pdev);
0167 
0168     return platform_driver_register(&xtensa_gpio_driver);
0169 }
0170 device_initcall(xtensa_gpio_init);
0171 
0172 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
0173 MODULE_DESCRIPTION("Xtensa LX4 GPIO32 driver");
0174 MODULE_LICENSE("GPL");