#include "updatetree.h" extern struct script *script; /*public functions */ int of_prop_string_count(const char *prop_val, int prop_len) { int l = 0, i = 0; const char *p, *end; p = prop_val; end = p + prop_len; for (i = 0; p < end; i++, p += l) { l = strnlen(p, end - p) + 1; if (p + l > end) return -1; } return i <= 0 ? -1 : i; } const char *of_prop_next_string(struct property *prop, const char *cur) { const char *curv = cur; if (!prop) return NULL; if (!cur) return prop->val.val; curv += strlen(cur) + 1; if (curv >= prop->val.val + prop->val.len) return NULL; return curv; } int sunxi_get_propval(struct node *node, const char *name) { unsigned int value; struct property *prop; cell_t *info = NULL; prop = get_property(node, name); if (prop) { info = (cell_t *)prop->val.val; value = fdt32_to_cpu(*info++); return value; } return -1; } int sunxi_gpio_to_name(int port, int port_num, char *name) { int index; if (!name) return -1; if ((port*32+port_num) >= 1024) { /* axp gpio name like this : GPIO0/GPIO1/.. */ index = (port-1)*32+port_num - 1024; sprintf(name, "GPIO%d", index); } else { /* sunxi gpio name like this : PA0/PA1/PB0 */ sprintf(name, "P%c%d", ('A' + (port-1)), port_num); } return 0; } /*these functions mainly to process pin subkey*/ #define PL_BASE (352) #define AXP_BASE (1024) void sunxi_dt_update_gpio_group(struct boot_info *bi, struct node *node, struct script_entry *ep, struct script_gpio_entry *entry) { char *pinctrl_name = NULL, *string; int val32, gpio_index, temp_val, phandle; char *axp_pin_name[] = {"axp_pio", "axp_gpio0", "axp_gpio1"}; bool axp_pin = false; int i; struct data d; struct property *prop; struct node *pinctrl_node; prop = get_property(node, ep->name); if (prop) delete_property(prop); gpio_index = (entry->port - 1) * 32 + entry->port_num; if (gpio_index < PL_BASE) pinctrl_name = "pio"; else if (gpio_index < AXP_BASE && gpio_index >= PL_BASE) pinctrl_name = "r_pio"; else axp_pin = true; if (axp_pin) { for (i = 0; i < 3; i++) { pinctrl_name = axp_pin_name[i]; pinctrl_node = sunxi_get_node(bi->dt, pinctrl_name); if (pinctrl_node) break; } } else { pinctrl_node = sunxi_get_node(bi->dt, pinctrl_name); } if (!pinctrl_node) { printf("warning:can't find gpio node %s\n", pinctrl_name); return; } string = malloc(7 * sizeof(unsigned int)); /*set gpio control */ phandle = get_node_phandle(bi->dt, pinctrl_node); val32 = cpu_to_fdt32(phandle); memcpy(string, (char *)&val32, sizeof(val32)); /*set gpio bank */ val32 = cpu_to_fdt32(entry->port-1); memcpy(string + 1 * sizeof(val32), (char *)&val32, sizeof(val32)); /*set gpio bank index */ val32 = cpu_to_fdt32(entry->port_num); memcpy(string + 2 * sizeof(val32), (char *)&val32, sizeof(val32)); /*set gpio mul */ val32 = cpu_to_fdt32(entry->data[0]); memcpy(string + 3 * sizeof(val32), (char *)&val32, sizeof(val32)); /*set gpio pull */ temp_val = entry->data[1] < 0 ? 0xFFFFFFFF : entry->data[1]; val32 = cpu_to_fdt32(temp_val); memcpy(string + 4 * sizeof(val32), (char *)&val32, sizeof(val32)); /*set gpio drive */ temp_val = entry->data[2] < 0 ? 0xFFFFFFFF : entry->data[2]; val32 = cpu_to_fdt32(temp_val); memcpy(string + 5 * sizeof(val32), (char *)&val32, sizeof(val32)); /*set gpio data */ temp_val = entry->data[3] < 0 ? 0xFFFFFFFF : entry->data[3]; val32 = cpu_to_fdt32(temp_val); memcpy(string + 6 * sizeof(val32), (char *)&val32, sizeof(val32)); d = data_copy_mem(string, 7 * sizeof(unsigned int)); prop = build_property(ep->name, d); add_property(node, prop); free(string); } int sunxi_dt_init_pinconf_prop(struct script_section *section, struct boot_info *bi, struct node *node, int sleep_state) { int i, len, phandle; cell_t *cp = NULL; struct list_entry *o; struct script_entry *ep; struct script_gpio_entry *entry; struct data d0; struct node *p_node = NULL; struct property *prop; struct property *pinctrl; /*remove pin config */ for_each_entry_in_section(section->entries, o) { ep = container_of(o, struct script_entry, entries); entry = container_of(ep, struct script_gpio_entry, entry); if (entry->data[0] == 2 || entry->data[0] == 3 || entry->data[0] == 4 || entry->data[0] == 5 || entry->data[0] == 7) { if (!sleep_state) prop = get_property(node, "pinctrl-0"); else prop = get_property(node, "pinctrl-1"); if (prop) { len = prop->val.len/sizeof(unsigned int); cp = (cell_t *)prop->val.val; for (i = 0; i < len; i++) { phandle = fdt32_to_cpu(*cp++); p_node = get_node_by_phandle(bi->dt, phandle); delete_node(p_node); } delete_property(prop); } /* build pinctrl-0 property */ d0 = data_copy_mem(NULL, 0); if (!sleep_state) pinctrl = build_property("pinctrl-0", d0); else pinctrl = build_property("pinctrl-1", d0); add_property(node, pinctrl); break; } } return 0; } cell_t sunxi_dt_add_new_node_to_pinctrl(struct node *pinctrl_node, const char *dev_name, const char *pname, char *gpio_name, int gpio_value[], struct boot_info *bi) { cell_t phandle; int i, value_32, len, str_len; char *label, node_name[32]; struct data d; struct node *child, *temp_node; struct property *prop; child = build_node(NULL, NULL); /* set label */ str_len = strlen(dev_name)+strlen("_pins_")+2; label = malloc(str_len); strcpy(label, dev_name); strcat(label, "_pins_"); for (i = 0; i < 8; i++) { label[str_len-2] = (char)(i+'a'); label[str_len-1] = '\0'; temp_node = sunxi_get_node(bi->dt, label); if (temp_node) continue; else break; } add_label(&child->labels, label); /*set node name*/ str_len = strlen(dev_name)+2; strcpy(node_name, dev_name); strcat(node_name, "@"); for (i = 0; i < 8; i++) { node_name[str_len-1] = (char)(i+'0'); node_name[str_len] = '\0'; temp_node = get_subnode(pinctrl_node, node_name); if (temp_node) continue; else break; } /* set node name and phandle*/ child->name = xstrdup(node_name); /* set fullpath */ child->fullpath = join_path(pinctrl_node->fullpath, child->name); /*set phandle*/ phandle = get_node_phandle(bi->dt, child); add_child(pinctrl_node, child); /*add property of pins */ d = data_copy_mem(gpio_name, strlen(gpio_name) + 1); prop = build_property("allwinner,pins", d); add_property(child, prop); d = data_copy_mem(dev_name, strlen(dev_name) + 1); prop = build_property("allwinner,function", d); add_property(child, prop); d = data_copy_mem(pname, strlen(pname) + 1); prop = build_property("allwinner,pname", d); add_property(child, prop); value_32 = cpu_to_fdt32(gpio_value[0]); len = sizeof(unsigned int); d = data_copy_mem((char *)&value_32, len); prop = build_property("allwinner,muxsel", d); add_property(child, prop); value_32 = cpu_to_fdt32(gpio_value[1]); len = sizeof(unsigned int); d = data_copy_mem((char *)&value_32, len); prop = build_property("allwinner,pull", d); add_property(child, prop); value_32 = cpu_to_fdt32(gpio_value[2]); len = sizeof(unsigned int); d = data_copy_mem((char *)&value_32, len); prop = build_property("allwinner,drive", d); add_property(child, prop); value_32 = cpu_to_fdt32(gpio_value[3]); len = sizeof(unsigned int); d = data_copy_mem((char *)&value_32, len); prop = build_property("allwinner,data", d); add_property(child, prop); return phandle; } int insert_pinconf_node(const char *section_name, struct boot_info *bi, struct node *node, struct script_entry *ep, const char *prop_name) { char gpio_name[32], *string; cell_t *cp, *info; int muxsel = 0, pull = 0, data = 0, drive = 0; int i, ret, len, gpio_value[4], phandle, phandle_count; struct node *pin_node; struct property *prop, *prop_temp; struct script_gpio_entry *entry; entry = container_of(ep, struct script_gpio_entry, entry); ret = sunxi_gpio_to_name(entry->port, entry->port_num, gpio_name); if (ret) return ret; gpio_value[0] = entry->data[0]; gpio_value[1] = entry->data[1] < 0 ? 0xFFFFFFFF : entry->data[1]; gpio_value[2] = entry->data[2] < 0 ? 0xFFFFFFFF : entry->data[2]; gpio_value[3] = entry->data[3] < 0 ? 0xFFFFFFFF : entry->data[3]; prop = get_property(node, prop_name); phandle_count = prop->val.len/sizeof(unsigned int); cp = (cell_t *)prop->val.val; for (i = 0; i < phandle_count; i++) { phandle = fdt32_to_cpu(*cp++); pin_node = get_node_by_phandle(bi->dt, phandle); if (pin_node) { /* if find a pinctrl node, check config*/ prop_temp = get_property(pin_node, "allwinner,muxsel"); if (prop_temp) { info = (cell_t *)prop_temp->val.val; muxsel = fdt32_to_cpu(*info++); } prop_temp = get_property(pin_node, "allwinner,pull"); if (prop_temp) { info = (cell_t *)prop_temp->val.val; pull = fdt32_to_cpu(*info++); } prop_temp = get_property(pin_node, "allwinner,drive"); if (prop_temp) { info = (cell_t *)prop_temp->val.val; drive = fdt32_to_cpu(*info++); } prop_temp = get_property(pin_node, "allwinner,data"); if (prop_temp) { info = (cell_t *)prop_temp->val.val; data = fdt32_to_cpu(*info++); } if (gpio_value[0] == muxsel && gpio_value[1] == pull && gpio_value[2] == drive && gpio_value[3] == data) { prop_temp = get_property(pin_node, "allwinner,pins"); if (prop_temp) { len = prop_temp->val.len + strlen(gpio_name) + 1; string = malloc(len); memcpy(string, prop_temp->val.val, prop_temp->val.len); memcpy(string + prop_temp->val.len, gpio_name, strlen(gpio_name)); string[len-1] = '\0'; free(prop_temp->val.val); prop_temp->val.val = malloc(len); memcpy(prop_temp->val.val, string, len); prop_temp->val.len = len; free(string); } prop_temp = get_property(pin_node, "allwinner,pname"); if (prop_temp) { len = prop_temp->val.len + strlen(ep->name) + 1; string = malloc(len); memcpy(string, prop_temp->val.val, prop_temp->val.len); memcpy(string + prop_temp->val.len, ep->name, strlen(ep->name)); string[len-1] = '\0'; free(prop_temp->val.val); prop_temp->val.val = malloc(len); memcpy(prop_temp->val.val, string, len); prop_temp->val.len = len; free(string); return 0; } } } } return -1; } void create_pinconf_node(const char *section_name, struct boot_info *bi, struct node *node, struct script_entry *ep, struct property *prop) { int value[4], phandle; char gpio_name[32], *propname; struct node *pinctrl = NULL; struct data d_pinctrl_x; struct property *pinctrl_x; struct script_gpio_entry *entry; entry = container_of(ep, struct script_gpio_entry, entry); sunxi_gpio_to_name(entry->port, entry->port_num, gpio_name); value[0] = entry->data[0]; value[1] = entry->data[1] < 0 ? 0xFFFFFFFF : entry->data[1]; value[2] = entry->data[2] < 0 ? 0xFFFFFFFF : entry->data[2]; value[3] = entry->data[3] < 0 ? 0xFFFFFFFF : entry->data[3]; if (entry->port * 32 < PL_BASE) pinctrl = sunxi_get_node(bi->dt, "pio"); else if (entry->port * 32 >= PL_BASE && entry->port < AXP_BASE) pinctrl = sunxi_get_node(bi->dt, "r_pio"); phandle = sunxi_dt_add_new_node_to_pinctrl(pinctrl, section_name, ep->name, gpio_name, value, bi); if (phandle) { d_pinctrl_x = data_append_cell(prop->val, phandle); propname = malloc(strlen(prop->name)); strcpy(propname, prop->name); delete_property(prop); pinctrl_x = build_property(propname, d_pinctrl_x); add_property(node, pinctrl_x); } } void sunxi_dt_update_pin_group_sleep(const char *section_name, struct boot_info *bi, struct node *node, struct script_entry *ep) { int ret = 0; char gpio_name[32] = {0}; struct property *prop; struct script_gpio_entry *entry; entry = container_of(ep, struct script_gpio_entry, entry); sunxi_gpio_to_name(entry->port, entry->port_num, gpio_name); prop = get_property(node, "pinctrl-1"); ret = insert_pinconf_node(section_name, bi, node, ep, "pinctrl-1"); if (ret) create_pinconf_node(section_name, bi, node, ep, prop); } void sunxi_dt_update_pin_group_default(const char *section_name, struct boot_info *bi, struct node *node, struct script_entry *ep) { int ret = 0; char gpio_name[32] = {0}; struct property *prop; struct script_gpio_entry *entry; entry = container_of(ep, struct script_gpio_entry, entry); sunxi_gpio_to_name(entry->port, entry->port_num, gpio_name); prop = get_property(node, "pinctrl-0"); ret = insert_pinconf_node(section_name, bi, node, ep, "pinctrl-0"); if (ret) create_pinconf_node(section_name, bi, node, ep, prop); } /*end process pinconf */ void sunxi_dt_update_propval_cells(const char *section_name, struct script_entry *ep, struct node *node) { int len; unsigned int value_32; char temp[32], *string; struct data d; struct property *prop; struct script_single_entry *entry; entry = container_of(ep, struct script_single_entry, entry); strcpy(temp, section_name); strcat(temp, "_used"); if (strcmp(ep->name, "used") == 0 || strcmp(ep->name, temp) == 0) { string = entry->value ? "okay" : "disabled"; len = strlen(string) + 1; prop = get_property(node, "status"); if (prop) { free(prop->val.val); prop->val.val = malloc(len); strcpy(prop->val.val, string); prop->val.len = len; } else { d = data_copy_mem(string, len); prop = build_property("status", d); add_property(node, prop); } } else { value_32 = cpu_to_fdt32(entry->value); len = sizeof(unsigned int); prop = get_property(node, ep->name); if (prop) { free(prop->val.val); prop->val.val = malloc(len); memcpy(prop->val.val, &value_32, len); prop->val.len = len; } else { d = data_copy_mem((char *)&value_32, len); prop = build_property(ep->name, d); add_property(node, prop); } } } void sunxi_dt_update_propval_string(const char *section_name, struct script_entry *ep, struct node *node) { int len; char *string; struct data d; struct property *prop; struct script_string_entry *entry; /*SCRIPT_VALUE_TYPE_STRING*/ entry = container_of(ep, struct script_string_entry, entry); string = entry->string; len = entry->l; prop = get_property(node, ep->name); if (prop) { free(prop->val.val); prop->val.val = malloc(len); strcpy(prop->val.val, string); prop->val.len = len; } else { d = data_copy_mem(string, len); prop = build_property(ep->name, d); add_property(node, prop); } } void sunxi_dt_update_propval_empty(const char *section_name, struct script_entry *ep, struct node *node) { struct data d = {0}; struct property *prop, *temp; struct script_null_entry *entry; /* SCRIPT_VALUE_TYPE_STRING */ entry = container_of(ep, struct script_null_entry, entry); prop = get_property(node, entry->entry.name); if (prop) delete_property(prop); temp = build_property(entry->entry.name, d); add_property(node, temp); } void sunxi_dt_update_propval_gpio(const char *section_name, struct script_entry *ep, struct node *node, struct boot_info *bi, int sleep_state) { struct script_gpio_entry *entry; entry = container_of(ep, struct script_gpio_entry, entry); switch (entry->data[0]) { case 0: case 1: case 6: sunxi_dt_update_gpio_group(bi, node, ep, entry); break; case 2: case 3: case 4: case 5: case 7: if (sleep_state) sunxi_dt_update_pin_group_sleep(section_name, bi, node, ep); else sunxi_dt_update_pin_group_default(section_name, bi, node, ep); break; } } struct node *sunxi_get_node(struct node *tree, const char *string) { struct node *nd; nd = get_node_by_label(tree, string); if (!nd) nd = get_node_by_type(tree, string); return nd; } int sunxi_build_new_node(struct boot_info *bi, char pnode_name[], char node_name[]) { char *label; struct node *child, *parent; parent = sunxi_get_node(bi->dt, pnode_name); child = build_node(NULL, NULL); if (!child) printf("build node faile[%s]\n", node_name); label = xstrdup(node_name); add_label(&child->labels, label); child->name = xstrdup(node_name); child->fullpath = join_path(parent->fullpath, child->name); add_child(parent, child); return 0; } int process_mainkey(char *mainkey, char parent_name[], char child_name[], int *state) { char *delim1 = "/"; char *delim2 = "_suspend"; char *buf = strstr(mainkey, delim1); char *temp_buf; if (buf != NULL) { sscanf(mainkey, "%[^/]/%[^@]", parent_name, child_name); } else { strcpy(parent_name, "soc"); strcpy(child_name, mainkey); } temp_buf = strstr(child_name, delim2); if (temp_buf != NULL) { memset(temp_buf, 0, strlen(temp_buf)); *state = 1; } else { *state = 0; } return 0; } int dt_update_source(const char *fexname, FILE *f, struct boot_info *bi) { int ret = 0; int sleep_state = false; char p_key[32] = {0}; char c_key[32] = {0}; struct node *sub_node, *parent_node; struct list_entry *sec_list, *o; struct script_section *section; struct script_entry *ep; struct property *device_type_prop; /*for build new device type property.*/ struct data d; struct property *new_prop; ret = script_parse(fexname); if (ret) { printf("parser sys_config.fex file failed.\n"); exit(1); } for_each_section_in_list(script->sections, sec_list) { section = container_of(sec_list, struct script_section, sections); /* * here mainly deal with section name like parent_key/child_key */ process_mainkey(section->name, p_key, c_key, &sleep_state); printf("p=%s c=%s state=%d\n", p_key, c_key, sleep_state); parent_node = sunxi_get_node(bi->dt, p_key); if (!parent_node) { printf("[SCRIPT_TO_DTS]Can not get parent node.\n"); exit(1); } sub_node = sunxi_get_node(bi->dt, c_key); if (!sub_node) { sunxi_build_new_node(bi, p_key, c_key); sub_node = sunxi_get_node(bi->dt, c_key); } device_type_prop = get_property(sub_node, "device_type"); if (!device_type_prop) { d = data_copy_mem(c_key, strlen(c_key)+1); new_prop = build_property("device_type", d); add_property(sub_node, new_prop); } sunxi_dt_init_pinconf_prop(section, bi, sub_node, sleep_state); for_each_entry_in_section(section->entries, o) { ep = container_of(o, struct script_entry, entries); switch (ep->type) { case 1: case 2: sunxi_dt_update_propval_cells(c_key, ep, sub_node); break; case 3: sunxi_dt_update_propval_string(c_key, ep, sub_node); break; case 5: sunxi_dt_update_propval_gpio(c_key, ep, sub_node, bi, sleep_state); break; case 6: /*empty property */ sunxi_dt_update_propval_empty(c_key, ep, sub_node); break; default: printf("input type error.\n"); break; } } } return 0; }