• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/mmio.h>
4 #include <console/console.h>
5 #include <gpio.h>
6 
7 /*
8  * Return family number and internal pad number in that community by pad number
9  * and which community it is in.
10  */
gpio_family_number(uint8_t community,uint8_t pad)11 uint16_t gpio_family_number(uint8_t community, uint8_t pad)
12 {
13 	/*
14 	 * Refer to BSW BIOS Writers Guide, Table "Family Number". BSW has 4 GPIO communities.
15 	 * Each community has up to 7 families and each family contains a range of Pad numbers.
16 	 * The number in the array is the maximum no. of that range.
17 	 * For example: East community, family 0, Pad 0~11.
18 	 */
19 	static const uint8_t community_base[GPIO_COMMUNITY_COUNT]
20 		[GPIO_FAMILIES_MAX_PER_COMM + 1] = {
21 		{0,  8, 16, 24, 32, 40, 48, 56}, /* Southwest */
22 		{0,  9, 22, 34, 46, 59, 59, 59}, /* North */
23 		{0, 12, 24, 24, 24, 24, 24, 24}, /* East */
24 		{0,  8, 20, 26, 34, 44, 55, 55}  /* Southeast */
25 	};
26 	const uint8_t *base;
27 	uint8_t i;
28 
29 	/* Validate the pad number */
30 	if (pad > community_base[community][7])
31 		die("Pad number is out of range!");
32 
33 	/* Locate the family number for the pad */
34 	base = &community_base[community][0];
35 	for (i = 0; i < 7; i++) {
36 		if ((pad >= base[0]) && (pad < base[1]))
37 			break;
38 		base++;
39 	}
40 
41 	/* Family number in high byte and inner pad number in lowest byte */
42 	return (i << 8) + pad - *base;
43 }
44 
45 /*
46  * Return pad configuration register offset by pad number and which community it is in.
47  */
gpio_pad_config_reg(uint8_t community,uint8_t pad)48 uint32_t *gpio_pad_config_reg(uint8_t community, uint8_t pad)
49 {
50 	uint16_t fpad;
51 	uint32_t *pad_config_reg;
52 
53 	/* Get the GPIO family number */
54 	fpad = gpio_family_number(community, pad);
55 
56 	/*
57 	 * Refer to BSW BIOS Writers Guide, Table "Per Pad Memory Space Registers Addresses"
58 	 * for the Pad configuration register calculation.
59 	 */
60 	pad_config_reg = (uint32_t *)(COMMUNITY_BASE(community) + FAMILY_PAD_REGS_OFF +
61 		(FAMILY_PAD_REGS_SIZE * (fpad >> 8)) + (GPIO_REGS_SIZE * (fpad & 0xff)));
62 
63 	return pad_config_reg;
64 }
65 
gpio_get_community_num(gpio_t gpio_num,int * pad)66 static int gpio_get_community_num(gpio_t gpio_num, int *pad)
67 {
68 	int comm = 0;
69 
70 	if (gpio_num >= GP_SW_00 && gpio_num <= GP_SW_97) {
71 		comm =  GP_SOUTHWEST;
72 		*pad = gpio_num % GP_SOUTHWEST_COUNT;
73 
74 	} else if (gpio_num >= GP_NC_00 && gpio_num <= GP_NC_72) {
75 		comm =  GP_NORTH;
76 		*pad = gpio_num % GP_SOUTHWEST_COUNT;
77 
78 	} else if (gpio_num >= GP_E_00 && gpio_num <= GP_E_26) {
79 		comm =  GP_EAST;
80 		*pad = gpio_num % (GP_SOUTHWEST_COUNT + GP_NORTH_COUNT);
81 
82 	} else {
83 		comm = GP_SOUTHEAST;
84 		*pad = gpio_num % (GP_SOUTHWEST_COUNT + GP_NORTH_COUNT + GP_EAST_COUNT);
85 	}
86 	return comm;
87 }
88 
gpio_config_pad(gpio_t gpio_num,const struct soc_gpio_map * cfg)89 static void gpio_config_pad(gpio_t gpio_num, const struct soc_gpio_map *cfg)
90 {
91 	int comm = 0;
92 	int pad_num = 0;
93 	uint32_t *pad_config0_reg;
94 	uint32_t *pad_config1_reg;
95 
96 	if (gpio_num > MAX_GPIO_CNT)
97 		return;
98 	/* Get GPIO Community based on GPIO_NUMBER */
99 	comm = gpio_get_community_num(gpio_num, &pad_num);
100 	/* CONF0 */
101 	pad_config0_reg = gpio_pad_config_reg(comm, pad_num);
102 	/* CONF1 */
103 	pad_config1_reg = pad_config0_reg + 1;
104 
105 	write32(pad_config0_reg, cfg->pad_conf0);
106 	write32(pad_config1_reg, cfg->pad_conf1);
107 }
108 
gpio_input_pullup(gpio_t gpio_num)109 void gpio_input_pullup(gpio_t gpio_num)
110 {
111 	struct soc_gpio_map cfg = GPIO_INPUT_PU_20K;
112 	gpio_config_pad(gpio_num, &cfg);
113 }
114 
gpio_input_pulldown(gpio_t gpio_num)115 void gpio_input_pulldown(gpio_t gpio_num)
116 {
117 	struct soc_gpio_map cfg = GPIO_INPUT_PD_20K;
118 	gpio_config_pad(gpio_num, &cfg);
119 }
120 
gpio_input(gpio_t gpio_num)121 void gpio_input(gpio_t gpio_num)
122 {
123 	struct soc_gpio_map cfg = GPIO_INPUT_NO_PULL;
124 	gpio_config_pad(gpio_num, &cfg);
125 }
126 
gpio_get(gpio_t gpio_num)127 int gpio_get(gpio_t gpio_num)
128 {
129 	int comm = 0;
130 	int pad_num = 0;
131 	uint32_t *pad_config0_reg;
132 	u32 pad_value;
133 
134 	if (gpio_num > MAX_GPIO_CNT)
135 		return -1;
136 
137 	/* Get GPIO Community based on GPIO_NUMBER */
138 	comm = gpio_get_community_num(gpio_num, &pad_num);
139 	/* CONF0 */
140 	pad_config0_reg = gpio_pad_config_reg(comm, pad_num);
141 
142 	pad_value = read32(pad_config0_reg);
143 
144 	return pad_value & PAD_RX_BIT;
145 }
146