/* * (C) Copyright 2007-2011 * Allwinner Technology Co., Ltd. * Tom Cubie * */ #include #include #include #include #include #include void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val) { u32 index = GPIO_CFG_INDEX(bank_offset); u32 offset = GPIO_CFG_OFFSET(bank_offset); clrsetbits_le32(&pio->cfg[0] + index, 0xf << offset, val << offset); } void sunxi_gpio_set_cfgpin(u32 pin, u32 val) { u32 bank = GPIO_BANK(pin); struct sunxi_gpio *pio = BANK_TO_GPIO(bank); sunxi_gpio_set_cfgbank(pio, pin, val); } int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset) { u32 index = GPIO_CFG_INDEX(bank_offset); u32 offset = GPIO_CFG_OFFSET(bank_offset); u32 cfg; cfg = readl(&pio->cfg[0] + index); cfg >>= offset; return cfg & 0xf; } int sunxi_gpio_get_cfgpin(u32 pin) { u32 bank = GPIO_BANK(pin); struct sunxi_gpio *pio = BANK_TO_GPIO(bank); return sunxi_gpio_get_cfgbank(pio, pin); } int sunxi_gpio_set_drv(u32 pin, u32 val) { u32 bank = GPIO_BANK(pin); u32 index = GPIO_DRV_INDEX(pin); u32 offset = GPIO_DRV_OFFSET(pin); struct sunxi_gpio *pio = BANK_TO_GPIO(bank); clrsetbits_le32(&pio->drv[0] + index, 0x3 << offset, val << offset); return 0; } int sunxi_gpio_set_pull(u32 pin, u32 val) { u32 bank = GPIO_BANK(pin); u32 index = GPIO_PULL_INDEX(pin); u32 offset = GPIO_PULL_OFFSET(pin); struct sunxi_gpio *pio = BANK_TO_GPIO(bank); clrsetbits_le32(&pio->pull[0] + index, 0x3 << offset, val << offset); return 0; } int boot_set_gpio(void *user_gpio_list, u32 group_count_max, int set_gpio) { normal_gpio_set_t *tmp_user_gpio_data, *gpio_list; u32 first_port; u32 tmp_group_func_data; u32 tmp_group_pull_data; u32 tmp_group_dlevel_data; u32 tmp_group_data_data; u32 data_change = 0; u32 port, port_num, port_num_func, port_num_pull, port_num_dlevel; u32 pre_port, pre_port_num_func, pre_port_num_dlevel; u32 pre_port_num_pull; volatile u32 *tmp_group_func_addr, *tmp_group_pull_addr; volatile u32 *tmp_group_dlevel_addr, *tmp_group_data_addr; int i, tmp_val; gpio_list = (normal_gpio_set_t *)user_gpio_list; /* printf("gpio: conut=%d, set gpio = %d\n", group_count_max, set_gpio); */ for (first_port = 0; first_port < group_count_max; first_port++) { tmp_user_gpio_data = gpio_list + first_port; port = tmp_user_gpio_data->port; port_num = tmp_user_gpio_data->port_num; if (!port) { continue; } /*32-bit register */ port_num_func = (port_num /(32/CFG_BIT_WIDTH)); port_num_pull = (port_num /(32/PULL_BIT_WIDTH)); port_num_dlevel = (port_num /(32/DRV_BIT_WIDTH)); if (port < 12) { tmp_group_func_addr = PIO_REG_CFG(port, port_num_func); tmp_group_pull_addr = PIO_REG_PULL(port, port_num_pull); tmp_group_dlevel_addr = PIO_REG_DLEVEL(port, port_num_dlevel); tmp_group_data_addr = PIO_REG_DATA(port); } else { tmp_group_func_addr = R_PIO_REG_CFG(port, port_num_func); tmp_group_pull_addr = R_PIO_REG_PULL(port, port_num_pull); tmp_group_dlevel_addr = R_PIO_REG_DLEVEL(port, port_num_dlevel); tmp_group_data_addr = R_PIO_REG_DATA(port); } tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); tmp_group_pull_data = GPIO_REG_READ(tmp_group_pull_addr); tmp_group_dlevel_data = GPIO_REG_READ(tmp_group_dlevel_addr); tmp_group_data_data = GPIO_REG_READ(tmp_group_data_addr); pre_port = port; pre_port_num_func = port_num_func; pre_port_num_pull = port_num_pull; pre_port_num_dlevel = port_num_dlevel; /* update funtion */ tmp_val = (port_num % (32/CFG_BIT_WIDTH)) * CFG_BIT_WIDTH; tmp_group_func_data &= ~(PIO_CFG_MASK << tmp_val); if (set_gpio) { tmp_group_func_data |= (tmp_user_gpio_data->mul_sel & PIO_CFG_MASK) << tmp_val; } /* update pull */ tmp_val = (port_num % (32/PULL_BIT_WIDTH)) * PULL_BIT_WIDTH; if (tmp_user_gpio_data->pull >= 0) { tmp_group_pull_data &= ~(0x03 << tmp_val); tmp_group_pull_data |= (tmp_user_gpio_data->pull & 0x03) << tmp_val; } /* update driver level */ tmp_val = (port_num % (32/DRV_BIT_WIDTH)) * DRV_BIT_WIDTH; if (tmp_user_gpio_data->drv_level >= 0) { tmp_group_dlevel_data &= ~(PIO_DRV_MASK << tmp_val); tmp_group_dlevel_data |= (tmp_user_gpio_data->drv_level & PIO_DRV_MASK) << tmp_val; } /* update data */ if (tmp_user_gpio_data->mul_sel == 1) { if (tmp_user_gpio_data->data >= 0) { tmp_val = tmp_user_gpio_data->data & 1; tmp_group_data_data &= ~(1 << port_num); tmp_group_data_data |= tmp_val << port_num; data_change = 1; } } break; } if (first_port >= group_count_max) { return -1; } for (i = first_port + 1; i < group_count_max; i++) { tmp_user_gpio_data = gpio_list + i; port = tmp_user_gpio_data->port; port_num = tmp_user_gpio_data->port_num; if (!port) { break; } port_num_func = (port_num /(32/CFG_BIT_WIDTH)); port_num_pull = (port_num /(32/PULL_BIT_WIDTH)); port_num_dlevel = (port_num /(32/DRV_BIT_WIDTH)); /* The same register is not written before and after */ if ((port_num_pull != pre_port_num_pull) || (port != pre_port)) { GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); GPIO_REG_WRITE(tmp_group_pull_addr, tmp_group_pull_data); GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data); if (data_change) { data_change = 0; GPIO_REG_WRITE(tmp_group_data_addr, tmp_group_data_data); } if (port < 12) { tmp_group_func_addr = PIO_REG_CFG(port, port_num_func); tmp_group_pull_addr = PIO_REG_PULL(port, port_num_pull); tmp_group_dlevel_addr = PIO_REG_DLEVEL(port, port_num_dlevel); tmp_group_data_addr = PIO_REG_DATA(port); } else { tmp_group_func_addr = R_PIO_REG_CFG(port, port_num_func); tmp_group_pull_addr = R_PIO_REG_PULL(port, port_num_pull); tmp_group_dlevel_addr = R_PIO_REG_DLEVEL(port, port_num_dlevel); tmp_group_data_addr = R_PIO_REG_DATA(port); } tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); tmp_group_pull_data = GPIO_REG_READ(tmp_group_pull_addr); tmp_group_dlevel_data = GPIO_REG_READ(tmp_group_dlevel_addr); tmp_group_data_data = GPIO_REG_READ(tmp_group_data_addr); } else if (pre_port_num_func != port_num_func || pre_port_num_dlevel != port_num_dlevel) { if (pre_port_num_func != port_num_func) { GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); if (port < 12) { tmp_group_func_addr = PIO_REG_CFG(port, port_num_func); } else { tmp_group_func_addr = R_PIO_REG_CFG(port, port_num_func); } tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); } if (pre_port_num_dlevel != port_num_dlevel) { GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data); if (port < 12) { tmp_group_dlevel_addr = PIO_REG_DLEVEL(port, port_num_dlevel); } else { tmp_group_dlevel_addr = PIO_REG_DLEVEL(port, port_num_dlevel); } tmp_group_dlevel_data = GPIO_REG_READ(tmp_group_dlevel_addr); } } pre_port_num_func = port_num_func; pre_port_num_pull = port_num_pull; pre_port_num_dlevel = port_num_dlevel; pre_port = port; /* write to the same register */ tmp_val = (port_num % (32/CFG_BIT_WIDTH)) * CFG_BIT_WIDTH; if (tmp_user_gpio_data->mul_sel >= 0) { tmp_group_func_data &= ~(PIO_CFG_MASK << tmp_val); if (set_gpio) { tmp_group_func_data |= (tmp_user_gpio_data->mul_sel & PIO_CFG_MASK) << tmp_val; } } tmp_val = (port_num % (32/PULL_BIT_WIDTH)) * PULL_BIT_WIDTH; if (tmp_user_gpio_data->pull >= 0) { tmp_group_pull_data &= ~(0x03 << tmp_val); tmp_group_pull_data |= (tmp_user_gpio_data->pull & 0x03) << tmp_val; } tmp_val = (port_num % (32/DRV_BIT_WIDTH)) * DRV_BIT_WIDTH; if (tmp_user_gpio_data->drv_level >= 0) { tmp_group_dlevel_data &= ~(PIO_DRV_MASK << tmp_val); tmp_group_dlevel_data |= (tmp_user_gpio_data->drv_level & PIO_DRV_MASK) << tmp_val; } if (tmp_user_gpio_data->mul_sel == 1) { if (tmp_user_gpio_data->data >= 0) { tmp_val = tmp_user_gpio_data->data & 1; tmp_group_data_data &= ~(1 << port_num); tmp_group_data_data |= tmp_val << port_num; data_change = 1; } } } /* for */ /* The last set of data written */ if (tmp_group_func_addr) { GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); GPIO_REG_WRITE(tmp_group_pull_addr, tmp_group_pull_data); GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data); if (data_change) { GPIO_REG_WRITE(tmp_group_data_addr, tmp_group_data_data); } } return 0; } #ifdef CFG_SET_GPIO_NEW /* Due to the incompatibility of port in the code, this function is redefined*/ int boot_set_gpio_new(void *user_gpio_list, u32 group_count_max, int set_gpio) { normal_gpio_set_t *tmp_user_gpio_data, *gpio_list; u32 first_port; u32 tmp_group_func_data; u32 tmp_group_pull_data; u32 tmp_group_dlevel_data; u32 tmp_group_data_data; u32 data_change = 0; u32 port, port_num, port_num_func, port_num_pull, port_num_dlevel; u32 pre_port, pre_port_num_func, pre_port_num_dlevel; u32 pre_port_num_pull; volatile u32 *tmp_group_func_addr, *tmp_group_pull_addr; volatile u32 *tmp_group_dlevel_addr, *tmp_group_data_addr; int i, tmp_val; gpio_list = (normal_gpio_set_t *)user_gpio_list; /* printf("gpio: conut=%d, set gpio = %d\n", group_count_max, set_gpio); */ for (first_port = 0; first_port < group_count_max; first_port++) { tmp_user_gpio_data = gpio_list + first_port; port = tmp_user_gpio_data->port; port_num = tmp_user_gpio_data->port_num; if (port == PORT_NO_USE || port_num == PORT_NUM_NO_USE) { continue; } /*32-bit register */ port_num_func = (port_num /(32/CFG_BIT_WIDTH)); port_num_pull = (port_num /(32/PULL_BIT_WIDTH)); port_num_dlevel = (port_num /(32/DRV_BIT_WIDTH)); if (port < 12) { tmp_group_func_addr = NEW_PIO_REG_CFG(port, port_num_func); tmp_group_pull_addr = NEW_PIO_REG_PULL(port, port_num_pull); tmp_group_dlevel_addr = NEW_PIO_REG_DLEVEL(port, port_num_dlevel); tmp_group_data_addr = NEW_PIO_REG_DATA(port); } else { tmp_group_func_addr = R_NEW_PIO_REG_CFG(port, port_num_func); tmp_group_pull_addr = R_NEW_PIO_REG_PULL(port, port_num_pull); tmp_group_dlevel_addr = R_NEW_PIO_REG_DLEVEL(port, port_num_dlevel); tmp_group_data_addr = R_NEW_PIO_REG_DATA(port); } tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); tmp_group_pull_data = GPIO_REG_READ(tmp_group_pull_addr); tmp_group_dlevel_data = GPIO_REG_READ(tmp_group_dlevel_addr); tmp_group_data_data = GPIO_REG_READ(tmp_group_data_addr); pre_port = port; pre_port_num_func = port_num_func; pre_port_num_pull = port_num_pull; pre_port_num_dlevel = port_num_dlevel; /* update funtion */ tmp_val = (port_num % (32/CFG_BIT_WIDTH)) * CFG_BIT_WIDTH; tmp_group_func_data &= ~(PIO_CFG_MASK << tmp_val); if (set_gpio) { tmp_group_func_data |= (tmp_user_gpio_data->mul_sel & PIO_CFG_MASK) << tmp_val; } /* update pull */ tmp_val = (port_num % (32/PULL_BIT_WIDTH)) * PULL_BIT_WIDTH; if (tmp_user_gpio_data->pull >= 0) { tmp_group_pull_data &= ~(0x03 << tmp_val); tmp_group_pull_data |= (tmp_user_gpio_data->pull & 0x03) << tmp_val; } /* update driver level */ tmp_val = (port_num % (32/DRV_BIT_WIDTH)) * DRV_BIT_WIDTH; if (tmp_user_gpio_data->drv_level >= 0) { tmp_group_dlevel_data &= ~(PIO_DRV_MASK << tmp_val); tmp_group_dlevel_data |= (tmp_user_gpio_data->drv_level & PIO_DRV_MASK) << tmp_val; } /* update data */ if (tmp_user_gpio_data->mul_sel == 1) { if (tmp_user_gpio_data->data >= 0) { tmp_val = tmp_user_gpio_data->data & 1; tmp_group_data_data &= ~(1 << port_num); tmp_group_data_data |= tmp_val << port_num; data_change = 1; } } break; } if (first_port >= group_count_max) { return -1; } for (i = first_port + 1; i < group_count_max; i++) { tmp_user_gpio_data = gpio_list + i; port = tmp_user_gpio_data->port; port_num = tmp_user_gpio_data->port_num; if (port == PORT_NO_USE || port_num == PORT_NUM_NO_USE) { continue; } port_num_func = (port_num /(32/CFG_BIT_WIDTH)); port_num_pull = (port_num /(32/PULL_BIT_WIDTH)); port_num_dlevel = (port_num /(32/DRV_BIT_WIDTH)); /* The same register is not written before and after */ if ((port_num_pull != pre_port_num_pull) || (port != pre_port)) { GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); GPIO_REG_WRITE(tmp_group_pull_addr, tmp_group_pull_data); GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data); if (data_change) { data_change = 0; GPIO_REG_WRITE(tmp_group_data_addr, tmp_group_data_data); } if (port < 12) { tmp_group_func_addr = NEW_PIO_REG_CFG(port, port_num_func); tmp_group_pull_addr = NEW_PIO_REG_PULL(port, port_num_pull); tmp_group_dlevel_addr = NEW_PIO_REG_DLEVEL(port, port_num_dlevel); tmp_group_data_addr = NEW_PIO_REG_DATA(port); } else { tmp_group_func_addr = R_NEW_PIO_REG_CFG(port, port_num_func); tmp_group_pull_addr = R_NEW_PIO_REG_PULL(port, port_num_pull); tmp_group_dlevel_addr = R_NEW_PIO_REG_DLEVEL(port, port_num_dlevel); tmp_group_data_addr = R_NEW_PIO_REG_DATA(port); } tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); tmp_group_pull_data = GPIO_REG_READ(tmp_group_pull_addr); tmp_group_dlevel_data = GPIO_REG_READ(tmp_group_dlevel_addr); tmp_group_data_data = GPIO_REG_READ(tmp_group_data_addr); } else if (pre_port_num_func != port_num_func || pre_port_num_dlevel != port_num_dlevel) { if (pre_port_num_func != port_num_func) { GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); if (port < 12) { tmp_group_func_addr = NEW_PIO_REG_CFG(port, port_num_func); } else { tmp_group_func_addr = R_NEW_PIO_REG_CFG(port, port_num_func); } tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); } if (pre_port_num_dlevel != port_num_dlevel) { GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data); if (port < 12) { tmp_group_dlevel_addr = NEW_PIO_REG_DLEVEL(port, port_num_dlevel); } else { tmp_group_dlevel_addr = NEW_PIO_REG_DLEVEL(port, port_num_dlevel); } tmp_group_dlevel_data = GPIO_REG_READ(tmp_group_dlevel_addr); } } pre_port_num_func = port_num_func; pre_port_num_pull = port_num_pull; pre_port_num_dlevel = port_num_dlevel; pre_port = port; /* write to the same register */ tmp_val = (port_num % (32/CFG_BIT_WIDTH)) * CFG_BIT_WIDTH; if (tmp_user_gpio_data->mul_sel >= 0) { tmp_group_func_data &= ~(PIO_CFG_MASK << tmp_val); if (set_gpio) { tmp_group_func_data |= (tmp_user_gpio_data->mul_sel & PIO_CFG_MASK) << tmp_val; } } tmp_val = (port_num % (32/PULL_BIT_WIDTH)) * PULL_BIT_WIDTH; if (tmp_user_gpio_data->pull >= 0) { tmp_group_pull_data &= ~(0x03 << tmp_val); tmp_group_pull_data |= (tmp_user_gpio_data->pull & 0x03) << tmp_val; } tmp_val = (port_num % (32/DRV_BIT_WIDTH)) * DRV_BIT_WIDTH; if (tmp_user_gpio_data->drv_level >= 0) { tmp_group_dlevel_data &= ~(PIO_DRV_MASK << tmp_val); tmp_group_dlevel_data |= (tmp_user_gpio_data->drv_level & PIO_DRV_MASK) << tmp_val; } if (tmp_user_gpio_data->mul_sel == 1) { if (tmp_user_gpio_data->data >= 0) { tmp_val = tmp_user_gpio_data->data & 1; tmp_group_data_data &= ~(1 << port_num); tmp_group_data_data |= tmp_val << port_num; data_change = 1; } } } /* for */ /* The last set of data written */ if (tmp_group_func_addr) { GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); GPIO_REG_WRITE(tmp_group_pull_addr, tmp_group_pull_data); GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data); if (data_change) { GPIO_REG_WRITE(tmp_group_data_addr, tmp_group_data_data); } } return 0; } #endif #ifdef CFG_SUNXI_FDT int fdt_get_one_gpio(const char *node_path, const char *prop_name, normal_gpio_cfg *gpio_list) { int nodeoffset; /* node offset from libfdt */ int ret; u32 data[10]; memset(data, 0, sizeof(data)); //get property vaule by handle nodeoffset = fdt_path_offset(working_fdt, node_path); if (nodeoffset < 0) { printf("fdt err returned %s\n", fdt_strerror(nodeoffset)); return -1; } ret = fdt_getprop_u32(working_fdt, nodeoffset, prop_name, data); if (ret < 0) { printf("%s :%s|%s err returned %s\n", __func__, node_path, prop_name, fdt_strerror(ret)); return -1; } // strcpy(gpio_list->gpio_name,prop_name); gpio_list->port = data[1]; //0: PA gpio_list->port_num = data[2]; gpio_list->mul_sel = data[3]; gpio_list->pull = data[4]; gpio_list->drv_level = data[5]; gpio_list->data = data[6]; boot_info( "port = %x,portnum=%x,mul_sel=%x,pull=%x drive= %x, data=%x\n", gpio_list->port, gpio_list->port_num, gpio_list->mul_sel, gpio_list->pull, gpio_list->drv_level, gpio_list->data); return 0; } #endif