mpc8xx_gpio.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2020 CS Group
  4. * Charles Frey <charles.frey@c-s.fr>
  5. *
  6. * based on driver/gpio/mpc8xxx_gpio.c, which is
  7. * Copyright 2016 Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
  8. *
  9. * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is
  10. * Copyright 2010 eXMeritus, A Boeing Company
  11. */
  12. #include <common.h>
  13. #include <asm/io.h>
  14. #include <dm.h>
  15. #include <mapmem.h>
  16. #include <asm/gpio.h>
  17. #include <malloc.h>
  18. enum {
  19. MPC8XX_CPM1_PORTA,
  20. MPC8XX_CPM1_PORTB,
  21. MPC8XX_CPM1_PORTC,
  22. MPC8XX_CPM1_PORTD,
  23. MPC8XX_CPM1_PORTE,
  24. };
  25. /*
  26. * The MPC885 CPU CPM has 5 I/O ports, and each ports has different
  27. * register length : 16 bits for ports A,C,D and 32 bits for ports
  28. * B and E.
  29. *
  30. * This structure allows us to select the accessors according to the
  31. * port we are configuring.
  32. */
  33. struct mpc8xx_gpio_data {
  34. /* The bank's register base in memory */
  35. void __iomem *base;
  36. /* The address of the registers; used to identify the bank */
  37. ulong addr;
  38. /* The GPIO count of the bank */
  39. uint gpio_count;
  40. /* Type needed to use the correct accessors */
  41. int type;
  42. };
  43. /* Structure for ports A, C, D */
  44. struct iop_16 {
  45. u16 pdir;
  46. u16 ppar;
  47. u16 podr;
  48. u16 pdat;
  49. };
  50. /* Port B */
  51. struct iop_32_b {
  52. u32 pdir;
  53. u32 ppar;
  54. u32 podr;
  55. u32 pdat;
  56. };
  57. /* Port E */
  58. struct iop_32_e {
  59. u32 pdir;
  60. u32 ppar;
  61. u32 psor;
  62. u32 podr;
  63. u32 pdat;
  64. };
  65. union iop_32 {
  66. struct iop_32_b b;
  67. struct iop_32_e e;
  68. };
  69. inline u32 gpio_mask(uint gpio, int type)
  70. {
  71. if (type == MPC8XX_CPM1_PORTB || type == MPC8XX_CPM1_PORTE)
  72. return 1U << (31 - (gpio));
  73. else
  74. return 1U << (15 - (gpio));
  75. }
  76. static inline u16 gpio16_get_val(void __iomem *base, u16 mask, int type)
  77. {
  78. struct iop_16 *regs = base;
  79. return in_be16(&regs->pdat) & mask;
  80. }
  81. static inline u16 gpio16_get_dir(void __iomem *base, u16 mask, int type)
  82. {
  83. struct iop_16 *regs = base;
  84. return in_be16(&regs->pdir) & mask;
  85. }
  86. static inline void gpio16_set_in(void __iomem *base, u16 gpios, int type)
  87. {
  88. struct iop_16 *regs = base;
  89. clrbits_be16(&regs->pdat, gpios);
  90. /* GPDIR register 0 -> input */
  91. clrbits_be16(&regs->pdir, gpios);
  92. }
  93. static inline void gpio16_set_lo(void __iomem *base, u16 gpios, int type)
  94. {
  95. struct iop_16 *regs = base;
  96. clrbits_be16(&regs->pdat, gpios);
  97. /* GPDIR register 1 -> output */
  98. setbits_be16(&regs->pdir, gpios);
  99. }
  100. static inline void gpio16_set_hi(void __iomem *base, u16 gpios, int type)
  101. {
  102. struct iop_16 *regs = base;
  103. setbits_be16(&regs->pdat, gpios);
  104. /* GPDIR register 1 -> output */
  105. setbits_be16(&regs->pdir, gpios);
  106. }
  107. /* PORT B AND E */
  108. static inline u32 gpio32_get_val(void __iomem *base, u32 mask, int type)
  109. {
  110. union iop_32 __iomem *regs = base;
  111. if (type == MPC8XX_CPM1_PORTB)
  112. return in_be32(&regs->b.pdat) & mask;
  113. else
  114. return in_be32(&regs->e.pdat) & mask;
  115. }
  116. static inline u32 gpio32_get_dir(void __iomem *base, u32 mask, int type)
  117. {
  118. union iop_32 __iomem *regs = base;
  119. if (type == MPC8XX_CPM1_PORTB)
  120. return in_be32(&regs->b.pdir) & mask;
  121. else
  122. return in_be32(&regs->e.pdir) & mask;
  123. }
  124. static inline void gpio32_set_in(void __iomem *base, u32 gpios, int type)
  125. {
  126. union iop_32 __iomem *regs = base;
  127. if (type == MPC8XX_CPM1_PORTB) {
  128. clrbits_be32(&regs->b.pdat, gpios);
  129. /* GPDIR register 0 -> input */
  130. clrbits_be32(&regs->b.pdir, gpios);
  131. } else { /* Port E */
  132. clrbits_be32(&regs->e.pdat, gpios);
  133. /* GPDIR register 0 -> input */
  134. clrbits_be32(&regs->e.pdir, gpios);
  135. }
  136. }
  137. static inline void gpio32_set_lo(void __iomem *base, u32 gpios, int type)
  138. {
  139. union iop_32 __iomem *regs = base;
  140. if (type == MPC8XX_CPM1_PORTB) {
  141. clrbits_be32(&regs->b.pdat, gpios);
  142. /* GPDIR register 1 -> output */
  143. setbits_be32(&regs->b.pdir, gpios);
  144. } else {
  145. clrbits_be32(&regs->e.pdat, gpios);
  146. /* GPDIR register 1 -> output */
  147. setbits_be32(&regs->e.pdir, gpios);
  148. }
  149. }
  150. static inline void gpio32_set_hi(void __iomem *base, u32 gpios, int type)
  151. {
  152. union iop_32 __iomem *regs = base;
  153. if (type == MPC8XX_CPM1_PORTB) {
  154. setbits_be32(&regs->b.pdat, gpios);
  155. /* GPDIR register 1 -> output */
  156. setbits_be32(&regs->b.pdir, gpios);
  157. } else {
  158. setbits_be32(&regs->e.pdat, gpios);
  159. /* GPDIR register 1 -> output */
  160. setbits_be32(&regs->e.pdir, gpios);
  161. }
  162. }
  163. static int mpc8xx_gpio_direction_input(struct udevice *dev, uint gpio)
  164. {
  165. struct mpc8xx_gpio_data *data = dev_get_priv(dev);
  166. int type = data->type;
  167. if (type == MPC8XX_CPM1_PORTB || type == MPC8XX_CPM1_PORTE)
  168. gpio32_set_in(data->base, gpio_mask(gpio, type), type);
  169. else
  170. gpio16_set_in(data->base, gpio_mask(gpio, type), type);
  171. return 0;
  172. }
  173. static int mpc8xx_gpio_set_value(struct udevice *dev, uint gpio, int value)
  174. {
  175. struct mpc8xx_gpio_data *data = dev_get_priv(dev);
  176. int type = data->type;
  177. if (type == MPC8XX_CPM1_PORTB || type == MPC8XX_CPM1_PORTE) {
  178. if (value)
  179. gpio32_set_hi(data->base, gpio_mask(gpio, type), type);
  180. else
  181. gpio32_set_lo(data->base, gpio_mask(gpio, type), type);
  182. } else {
  183. if (value)
  184. gpio16_set_hi(data->base, gpio_mask(gpio, type), type);
  185. else
  186. gpio16_set_lo(data->base, gpio_mask(gpio, type), type);
  187. }
  188. return 0;
  189. }
  190. static int mpc8xx_gpio_direction_output(struct udevice *dev, uint gpio,
  191. int value)
  192. {
  193. return mpc8xx_gpio_set_value(dev, gpio, value);
  194. }
  195. static int mpc8xx_gpio_get_value(struct udevice *dev, uint gpio)
  196. {
  197. struct mpc8xx_gpio_data *data = dev_get_priv(dev);
  198. int type = data->type;
  199. /* Input -> read value from GPDAT register */
  200. if (type == MPC8XX_CPM1_PORTB || type == MPC8XX_CPM1_PORTE)
  201. return gpio32_get_val(data->base, gpio_mask(gpio, type), type);
  202. else
  203. return gpio16_get_val(data->base, gpio_mask(gpio, type), type);
  204. }
  205. static int mpc8xx_gpio_get_function(struct udevice *dev, uint gpio)
  206. {
  207. struct mpc8xx_gpio_data *data = dev_get_priv(dev);
  208. int type = data->type;
  209. int dir;
  210. if (type == MPC8XX_CPM1_PORTB || type == MPC8XX_CPM1_PORTE)
  211. dir = gpio32_get_dir(data->base, gpio_mask(gpio, type), type);
  212. else
  213. dir = gpio16_get_dir(data->base, gpio_mask(gpio, type), type);
  214. return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
  215. }
  216. static int mpc8xx_gpio_ofdata_to_platdata(struct udevice *dev)
  217. {
  218. struct mpc8xx_gpio_plat *plat = dev_get_plat(dev);
  219. fdt_addr_t addr;
  220. u32 reg[2];
  221. dev_read_u32_array(dev, "reg", reg, 2);
  222. addr = dev_translate_address(dev, reg);
  223. plat->addr = addr;
  224. plat->size = reg[1];
  225. plat->ngpios = dev_read_u32_default(dev, "ngpios", 32);
  226. return 0;
  227. }
  228. static int mpc8xx_gpio_platdata_to_priv(struct udevice *dev)
  229. {
  230. struct mpc8xx_gpio_data *priv = dev_get_priv(dev);
  231. struct mpc8xx_gpio_plat *plat = dev_get_plat(dev);
  232. unsigned long size = plat->size;
  233. int type;
  234. if (size == 0)
  235. size = 0x100;
  236. priv->addr = plat->addr;
  237. priv->base = map_sysmem(plat->addr, size);
  238. if (!priv->base)
  239. return -ENOMEM;
  240. priv->gpio_count = plat->ngpios;
  241. type = dev_get_driver_data(dev);
  242. if ((type == MPC8XX_CPM1_PORTA || type == MPC8XX_CPM1_PORTC ||
  243. type == MPC8XX_CPM1_PORTD) && plat->ngpios == 32)
  244. priv->gpio_count = 16;
  245. priv->type = type;
  246. return 0;
  247. }
  248. static int mpc8xx_gpio_probe(struct udevice *dev)
  249. {
  250. struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  251. struct mpc8xx_gpio_data *data = dev_get_priv(dev);
  252. char name[32], *str;
  253. mpc8xx_gpio_platdata_to_priv(dev);
  254. snprintf(name, sizeof(name), "MPC@%lx_", data->addr);
  255. str = strdup(name);
  256. if (!str)
  257. return -ENOMEM;
  258. uc_priv->bank_name = str;
  259. uc_priv->gpio_count = data->gpio_count;
  260. return 0;
  261. }
  262. static const struct dm_gpio_ops gpio_mpc8xx_ops = {
  263. .direction_input = mpc8xx_gpio_direction_input,
  264. .direction_output = mpc8xx_gpio_direction_output,
  265. .get_value = mpc8xx_gpio_get_value,
  266. .set_value = mpc8xx_gpio_set_value,
  267. .get_function = mpc8xx_gpio_get_function,
  268. };
  269. static const struct udevice_id mpc8xx_gpio_ids[] = {
  270. { .compatible = "fsl,cpm1-pario-bank-a", .data = MPC8XX_CPM1_PORTA },
  271. { .compatible = "fsl,cpm1-pario-bank-b", .data = MPC8XX_CPM1_PORTB },
  272. { .compatible = "fsl,cpm1-pario-bank-c", .data = MPC8XX_CPM1_PORTC },
  273. { .compatible = "fsl,cpm1-pario-bank-d", .data = MPC8XX_CPM1_PORTD },
  274. { .compatible = "fsl,cpm1-pario-bank-e", .data = MPC8XX_CPM1_PORTE },
  275. { /* sentinel */ }
  276. };
  277. U_BOOT_DRIVER(gpio_mpc8xx) = {
  278. .name = "gpio_mpc8xx",
  279. .id = UCLASS_GPIO,
  280. .ops = &gpio_mpc8xx_ops,
  281. .of_to_plat = mpc8xx_gpio_ofdata_to_platdata,
  282. .plat_auto = sizeof(struct mpc8xx_gpio_plat),
  283. .of_match = mpc8xx_gpio_ids,
  284. .probe = mpc8xx_gpio_probe,
  285. .priv_auto = sizeof(struct mpc8xx_gpio_data),
  286. };