u-boot/u-boot/board/ar7240/carambola2/carambola2.c

471 lines
10 KiB
C

#include <common.h>
#include <command.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <config.h>
#include <version.h>
#include "ar7240_soc.h"
extern void ar7240_ddr_initial_config(uint32_t refresh);
extern int ar7240_ddr_find_size(void);
void
ar7240_usb_initial_config(void)
{
#ifndef CONFIG_HORNET_EMU
ar7240_reg_wr_nf(AR7240_USB_PLL_CONFIG, 0x0a04081e);
ar7240_reg_wr_nf(AR7240_USB_PLL_CONFIG, 0x0804081e);
#endif
}
#ifdef CONFIG_SHOW_BOOT_PROGRESS
int ar7240_boot_status = 0; // Global variable to indicate if boot is succesful
// negative values show failure
#endif
typedef struct reg_conf{
unsigned int addr;
unsigned int set_mask;
unsigned int clear_mask;
};
// Carambola2 GPIO LED definition
typedef struct gpio_led_desc {
int id;
int bit; //GPIO bit
int polarity; //1 - high active; 0 - low active
int disable; //1 - disable led, 0 - enable
};
int led_count=5;
struct gpio_led_desc leds[]={
{// WLAN LED
.id=0,
.bit=0,
.polarity=0,
.disable=0
},
{// ETH0_LED
.id=1,
.bit=13,
.polarity=1,
.disable=0
},
{// ETH1_LED
.id=2,
.bit=14,
.polarity=1,
.disable=0
},
{// USB recovery indication
.id=3,
.bit=0,
.polarity=0,
.disable=0
},
{// Nothing
.id=4,
.bit=0,
.polarity=0,
.disable=1
}
};
struct gpio_led_desc buttons[]={
{// USB Boot
.id=0,
.bit=11,
.polarity=0,
.disable=0
},
{// Nothing
.id=1,
.bit=0,
.polarity=0,
.disable=1
},
{// Nothing
.id=2,
.bit=0,
.polarity=0,
.disable=1
},
{// Nothing
.id=3,
.bit=0,
.polarity=0,
.disable=1
},
{// Nothing
.id=4,
.bit=0,
.polarity=0,
.disable=1
}
};
void
ar7240_usb_otp_config(void)
{
unsigned int addr, reg_val, reg_usb;
int time_out, status, usb_valid;
for (addr = 0xb8114014; ;addr -= 0x10) {
status = 0;
time_out = 20;
reg_val = ar7240_reg_rd(addr);
while ((time_out > 0) && (~status)) {
if ((( ar7240_reg_rd(0xb8115f18)) & 0x7) == 0x4) {
status = 1;
} else {
status = 0;
}
time_out--;
}
reg_val = ar7240_reg_rd(0xb8115f1c);
if ((reg_val & 0x80) == 0x80){
usb_valid = 1;
reg_usb = reg_val & 0x000000ff;
}
if (addr == 0xb8114004) {
break;
}
}
if (usb_valid) {
reg_val = ar7240_reg_rd(0xb8116c88);
reg_val &= ~0x03f00000;
reg_val |= (reg_usb & 0xf) << 22;
ar7240_reg_wr(0xb8116c88, reg_val);
}
}
void assign_gpio(void *data, int item_count1, int* tmp_item)
{
struct reg_conf *regs;
regs = (struct reg_conf*)data;
regs[item_count1].addr = tmp_item[0];
regs[item_count1].set_mask = tmp_item[1];
regs[item_count1].clear_mask = tmp_item[2];
return;
}
void assign_leds(void *data, int item_count1, int* tmp_item)
{
if (tmp_item[0]<5 && tmp_item[0]>=0){
int id=tmp_item[0];
leds[id].id = id;
leds[id].bit = tmp_item[1];
leds[id].polarity = tmp_item[2];
leds[id].disable = tmp_item[3];
}
return;
}
void assign_buttons(void *data, int item_count1, int* tmp_item)
{
if (tmp_item[0]<5 && tmp_item[0]>=0){
int id=tmp_item[0];
buttons[id].id = id;
buttons[id].bit = tmp_item[1];
buttons[id].polarity = tmp_item[2];
buttons[id].disable = tmp_item[3];
}
return;
}
int convert_hex(char* str, int item_nr)
{
return (simple_strtol(str, NULL, 16));
}
int convert_dec(char* str, int item_nr)
{
return (simple_strtol(str, NULL, 10));
}
int count_args(char* env)
{
char* pos;
pos = strchr(env,'/');
unsigned int reg_count=1;
while (pos != NULL){
reg_count++;
pos = strchr(pos+1,'/');
}
return reg_count;
}
int parse_config(char* env, int max_args, void *regs, int *reg_count,
void (*assign)(void*, int, int*),
int (*convert)(char*, int) )
{
char *tmp_str1, *tmp_str2, *tok1, *tok2;
int item_count1=0;
int item_count2;
int* tmp_item = malloc((sizeof(int))*max_args);
if (tmp_item == NULL){
return (-1);
}
tmp_str1 = strdup(env);
tok1=strsep(&tmp_str1, "/");
while (tok1 != NULL){
item_count2=0;
tmp_str2 = strdup(tok1);
tok2=strsep(&tmp_str2, ":");
while (tok2 != NULL){
item_count2++;
if (item_count2 > max_args)
break;
tmp_item[item_count2-1] = convert(tok2,item_count2);
tok2=strsep(&tmp_str2, ":");
}
if (item_count2 == max_args){
assign(regs, item_count1, tmp_item);
item_count1++;
}
tok1 = strsep(&tmp_str1, "/");
}
*reg_count = item_count1;
free(tmp_item);
return (0);
}
void apply_config(struct reg_conf *regs, int reg_count)
{
int i;
for (i=0; i<reg_count; i++){
//Check if given registers belong to GPIO range
if ((regs[i].addr>=0x18040000) && (regs[i].addr<=0x18040044)){
ar7240_reg_wr(regs[i].addr, ((ar7240_reg_rd(regs[i].addr)|regs[i].set_mask)&(~regs[i].clear_mask)));
}
else{
printf("Reg: %x is not in valid GPIO range\n", regs[i].addr);
}
}
return;
}
void gpio_env_init(int mode)
{
int max_args;
void (*assign)(struct reg_conf*, int, int*);
int (*convert)(char* ,int);
char* gpio_env;
int ret;
struct reg_conf *regs;
int reg_count;
int i;
if (mode==0){
assign = &assign_gpio;
convert = &convert_hex;
max_args = 3;
gpio_env = getenv("gpio_config");
}
else{
convert = &convert_dec;
max_args = 4;
if (mode==1){
assign = &assign_leds;
gpio_env = getenv("led_config");
}
else if(mode == 2){
assign = &assign_buttons;
gpio_env = getenv("button_config");
}
}
if (gpio_env == NULL){
if (mode==0){
//Default init
//set output enable
ar7240_reg_wr (AR7240_GPIO_OE, (ar7240_reg_rd(AR7240_GPIO_OE) | (1<<13)|(1<<14)|(1<<0) ));
//set ETH0 ETH1 LED output to high
ar7240_reg_wr (AR7240_GPIO_SET, (1<<13)|(1<<14));
//set WLAN LED output to low (reverse polarity LED)
ar7240_reg_wr (AR7240_GPIO_CLEAR, (1<<0));
//Enable USB boot sense GPIO as input
ar7240_reg_wr (AR7240_GPIO_OE, (ar7240_reg_rd(AR7240_GPIO_OE) & ~(1<<11)));
}
return;
}
reg_count = count_args(gpio_env);
if (mode==0){
regs = malloc(sizeof(struct reg_conf)*reg_count);
if (regs == NULL)
return;
}
else
regs = NULL;
ret = parse_config(gpio_env, max_args, (void*)regs, &reg_count, assign, convert);
if (ret<0)
return;
if (mode==0)
apply_config(regs, reg_count);
free(regs);
return;
}
void ar7240_gpio_config(void)
{
/* Disable clock obs
* clk_obs1(gpio13/bit8), clk_obs2(gpio14/bit9), clk_obs3(gpio15/bit10),
* clk_obs4(gpio16/bit11), clk_obs5(gpio17/bit12)
* clk_obs0(gpio1/bit19), 6(gpio11/bit20)
*/
ar7240_reg_wr (AR7240_GPIO_FUNC,
(ar7240_reg_rd(AR7240_GPIO_FUNC) & ~((0x1f<<8)|(0x3<<19))));
/* Enable eth Switch LEDs */
//ar7240_reg_wr (AR7240_GPIO_FUNC, (ar7240_reg_rd(AR7240_GPIO_FUNC) | (0x1f<<3)));
/* Clear AR7240_GPIO_FUNC BIT2 to ensure that software can control LED5(GPIO16) and LED6(GPIO17) */
ar7240_reg_wr (AR7240_GPIO_FUNC, (ar7240_reg_rd(AR7240_GPIO_FUNC) & ~(0x1<<2)));
/* Set HORNET_BOOTSTRAP_STATUS BIT18 to ensure that software can control GPIO26 and GPIO27 */
//ar7240_reg_wr (HORNET_BOOTSTRAP_STATUS, (ar7240_reg_rd(HORNET_BOOTSTRAP_STATUS) | (0x1<<18)));
}
int button_read(int button_id){
if (buttons[button_id].disable != 1){
if (((ar7240_reg_rd(AR7240_GPIO_IN)>>buttons[button_id].bit)&0x01) == buttons[button_id].polarity)
return 1;
else
return 0;
}
else
return -1;
}
#ifdef CONFIG_SHOW_ACTIVITY
void ar7240_gpio_led_switch(int led_id, int state)
//switch LED (led_id is defined in struct[] leds) to state (0 - off, 1 -on)
{
int i;
for (i=0; i<led_count;i++){
if (leds[i].disable != 1){
if (leds[i].id==led_id) {
if ((!leds[i].polarity) ^ state){
ar7240_reg_wr (AR7240_GPIO_SET, (1<<leds[i].bit));
}
else{
ar7240_reg_wr (AR7240_GPIO_CLEAR, (1<<leds[i].bit));
}
break;
}
}
}
return;
}
void ar7240_gpio_leds_off(void)
{
int i;
for (i=0; i<led_count;i++){
if (leds[i].disable != 1){
ar7240_gpio_led_switch(i, 0);
}
}
}
// Call after relocation
void custom_gpio_init(void)
{
//init GPIO, LED and button config
gpio_env_init(0); // custom GPIO init, turns on all LEDs
gpio_env_init(1); //LEDs
gpio_env_init(2); //BUTTONs
udelay(100 * 1000); // 100ms delay
ar7240_gpio_leds_off();
}
void show_activity(int arg)
{
uint32_t time = 0;
static uint32_t led = 0;
time =get_timer(0);
if ( (ar7240_boot_status<0) )
{
//Blink 3 first LEDs in descriptor together
led += 1;
if (led > 2) led = 0;
ar7240_gpio_led_switch(led ,(time>>24)&0x01);
}
return;
}
#endif
#ifdef CONFIG_SHOW_BOOT_PROGRESS
void show_boot_progress(int arg)
{
ar7240_boot_status = arg;
return;
}
#endif
int
ar7240_mem_config(void)
{
#ifndef COMPRESSED_UBOOT
unsigned int tap_val1, tap_val2;
#endif
ar7240_gpio_config(); // init GPIO
ar7240_ddr_initial_config(CFG_DDR_REFRESH_VAL);
/* Default tap values for starting the tap_init*/
ar7240_reg_wr (AR7240_DDR_TAP_CONTROL0, CFG_DDR_TAP0_VAL);
ar7240_reg_wr (AR7240_DDR_TAP_CONTROL1, CFG_DDR_TAP1_VAL);
#ifndef COMPRESSED_UBOOT
ar7240_ddr_tap_init();
tap_val1 = ar7240_reg_rd(0xb800001c);
tap_val2 = ar7240_reg_rd(0xb8000020);
debug("#### TAP VALUE 1 = %x, 2 = %x\n",tap_val1, tap_val2);
#endif
ar7240_usb_initial_config();
ar7240_usb_otp_config();
//hornet_ddr_tap_init();
return (ar7240_ddr_find_size());
}
long int initdram(int board_type)
{
return (ar7240_mem_config());
}
#ifdef COMPRESSED_UBOOT
int checkboard (char *board_string)
{
strcpy(board_string, "sysmocom "CARABOOT_RELEASE" (AR9331) U-boot");
return 0;
}
#else
int checkboard (void)
{
printf("sysmcom "CARABOOT_RELEASE" (AR9331) U-boot\n");
return 0;
}
#endif /* #ifdef COMPRESSED_UBOOT */