SmartAudio/lichee/linux-4.9/scripts/dtc/updatetree.c

744 lines
18 KiB
C
Executable File

#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;
}