From d8e5d25dc25f7c588eda9e176465502208111e3a Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 11 Mar 2010 08:40:51 +0530 Subject: arm: add printascii in printk option Signed-off-by: Rabin Vincent Change-Id: Ie73cf9782ccbf3a974383fa5d1474613c660c6b9 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/3172 Tested-by: Mian Yousaf KAUKAB Reviewed-by: Srinidhi KASAGAR Signed-off-by: Mian Yousaf Kaukab --- arch/arm/Kconfig.debug | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch') diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 85348a09d65..6ca82db8d21 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -318,6 +318,15 @@ config EARLY_PRINTK kernel low-level debugging functions. Add earlyprintk to your kernel parameters to enable this console. +config PRINTK_LL + bool "Use printascii in printk" + depends on DEBUG_LL + help + Say Y here if you want to have printk send its output via the + kernel low-level debugging functions. This is useful if you + are debugging code that executes before the earlyprintk console + is initialized. + config OC_ETM bool "On-chip ETM and ETB" depends on ARM_AMBA -- cgit v1.2.3 From a4f60cc32fdd87e7cc2c85275bc4f667a6b60d56 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Thu, 20 Oct 2011 10:50:37 +0200 Subject: ARM: ux500: hwreg debugfs: access DB8500 registers from debugfs entries Patch used for test purpose only. It is not plan to mainline it. Create debugfs entries to read/write specific DB8500 physical addresses. This is quite useless since devmem allows this userland access. However, debugfs entries are easier for scripting purpose. Check the debugfs entries usage from heading comments in hwreg.c ST-Ericsson Linux next: Not to be mainlined ST-Ericsson ID: - ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Id202562030a144d5c2c1aaa3e67e7f4de60c2cb2 Signed-off-by: carriere etienne Signed-off-by: Jonas Aaberg Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/17831 --- arch/arm/mach-ux500/hwreg.c | 660 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 660 insertions(+) create mode 100644 arch/arm/mach-ux500/hwreg.c (limited to 'arch') diff --git a/arch/arm/mach-ux500/hwreg.c b/arch/arm/mach-ux500/hwreg.c new file mode 100644 index 00000000000..7ba3e0f2911 --- /dev/null +++ b/arch/arm/mach-ux500/hwreg.c @@ -0,0 +1,660 @@ +/* + * Copyright (C) 2011 ST-Ericsson SA + * + * Author: Etienne CARRIERE for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + * + * HWREG: debug purpose module to map declared IOs and read/write + * access from debugfs entries. + * + * HWREG 32bit DB8500 v2.0 register access + * ======================================= + * + * 32bit read: + * # echo > /mem/reg-addr + * # cat /mem/reg-val + * + * 32bit write: + * # echo > /mem/reg-addr + * # echo > /mem/reg-val + * + * 0x-prefixed hexadecimal + * decimal or 0x-prefixed hexadecimal + * + * HWREG DB8500 formated read/write access + * ======================================= + * + * Read: read data, data>>SHIFT, data&=MASK, output data + * [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE + * Write: read data, data &= ~(MASK< [0xAB123F98] + * + * Usage: + * # echo "CMD [OPTIONS] ADRESS [VALUE]" > $debugfs/mem/hwreg + * + * CMD read read access + * write write access + * + * ADDRESS target reg physical addr (0x-hexa) + * + * VALUE (write) value to be updated + * + * OPTIONS + * -d|-dec (read) output in decimal + * -h|-hexa (read) output in 0x-hexa (default) + * -l|-w|-b 32bit (default), 16bit or 8bit reg access + * -m|-mask MASK 0x-hexa mask (default 0xFFFFFFFF) + * -s|-shift SHIFT bit shift value (read:left, write:right) + * -o|-offset OFFSET address offset to add to ADDRESS value + * + * Warning: bit shift operation is applied to bit-mask. + * Warning: bit shift direction depends on read or right command. + * + * Examples: + * + * before: [*ADDRESS = 0xABCDEF98] + * # echo read -h -mask 0xFFF -shift 12 ADDRESS > hwreg + * # cat hwreg-shift + * 0x0000CDE + * # echo write -h -mask 0xFFF -shift 12 ADDRESS 0x123 > hwreg + * # cat hwreg-shift + * 0x0000123 + * after [*ADDRESS = 0xAB123F98] + * + * before: [*ADDRESS = 0xABCDEF98] + * # echo read -h -mask 0x00F0F000 ADDRESS 0x12345678 > hwreg + * # cat hwreg-shift + * 0x00C0E000 + * # echo write -h -mask 0x00F0F000 ADDRESS 0x12345678 > hwreg + * # cat hwreg-shift + * 0xAB3D5F98 + * after [*ADDRESS = 0xAB123F98] + * + * Read DB8500 version (full ID, chip version ID, chip version ID): + * + * echo read 0x9001DBF4 > hwreg + * cat hwreg + * echo read -m 0xFFFF -s 8 0x9001DBF4 > hwreg + * cat hwreg + * echo read -m 0xFF -s 0 0x9001DBF4 > hwreg + * cat hwreg + * + * Read and Enable/Disable I2C PRCMU clock: + * + * printf "I2CCLK = " && echo read -m 1 -s 8 0x80157520 > hwreg + * cat /sys/kernel/debug/db8500/hwreg + * printf "I2CCLK off" && echo write -m 1 -s 8 0x80157518 1 > hwreg + * printf "I2CCLK on" && echo write -m 1 -s 8 0x80157510 1 > hwreg + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* + * temporary definitions + * The following declarations are to be removed + * when kernel/arch/arm/mach-ux8500/include/mach/db8500-regs.h is up-to-date + */ + +/* DDR-SDRAM chip-select 0 (0x0000 0000 : 0x1FFF FFFF) */ +#ifndef U8500_SCU_CD_R4_BASE +#define U8500_SCU_CD_R4_BASE 0x17c40000 +#endif + +#ifndef U8500_SCU_AD_R4_BASE +#define U8500_SCU_AD_R4_BASE 0x17d40000 +#endif + +#ifndef U8500_HSI2CMODEMR4_BASE +#define U8500_HSI2CMODEMR4_BASE 0x17e02000 +#endif +/* End of temporary definitions */ + +static struct dentry *hwreg_debugfs_dir; + +/* 32bit read/write ressources */ +static u32 debug_address; /* shared: single read/write access */ + +/* hwreg entry ressources */ +struct hwreg_cfg { + uint addr; /* target physical addr to access */ + uint fmt; /* format */ + uint mask; /* read/write mask, applied before any bit shift */ + int shift; /* bit shift (read:right shift, write:left shift */ +}; +#define REG_FMT_DEC(c) ((c)->fmt & 0x1) /* bit 0: 0=hexa, 1=dec */ +#define REG_FMT_HEX(c) (!REG_FMT_DEC(c)) /* bit 0: 0=hexa, 1=dec */ +#define REG_FMT_32B(c) (((c)->fmt & 0x6)==0x0) /* bit[2:1]=0 => 32b access */ +#define REG_FMT_16B(c) (((c)->fmt & 0x6)==0x2) /* bit[2:1]=1 => 16b access */ +#define REG_FMT_8B(c) (((c)->fmt & 0x6)==0x4) /* bit[2:1]=2 => 8b access */ + +static struct hwreg_cfg hwreg_cfg = { + .addr = 0, /* default: invalid phys addr */ + .fmt = 0, /* default: 32bit access, hex output */ + .mask = 0xFFFFFFFF, /* default: no mask */ + .shift = 0, /* default: no bit shift */ +}; + +/* HWREG guts: mapping table */ + +struct hwreg_io_range { + u32 base; + u32 size; + u8 *addr; +}; + +/* + * HWREG guts: mapping table + */ +static struct hwreg_io_range hwreg_io_map[] = { + /* Periph1 Peripherals */ + {.base = U8500_PER1_BASE, .size = 0x10000}, + /* Periph2 Peripherals */ + {.base = U8500_PER2_BASE, .size = 0x10000}, + /* Periph3 Peripherals */ + {.base = U8500_PER3_BASE, .size = 0x10000}, + /* Periph4 Peripherals */ + {.base = U8500_PER4_BASE, .size = 0x70000}, + /* Periph5 Periphals */ + {.base = U8500_PER5_BASE, .size = 0x20000}, + /* Periph6 Peripherals */ + {.base = U8500_PER6_BASE, .size = 0x10000}, + /* + * Snoop Control Unit, A9 Private interrupt IF, + * A9 private peripherals, Level-2 Cache Configuration registers, + * and some reserved area + */ + {.base = U8500_SCU_BASE, .size = 0x4000}, + + /* DISPLAY Ctrl. configuration registers */ + {.base = U8500_MCDE_BASE, .size = SZ_4K}, + + /* DSI1 link registers */ + {.base = U8500_DSI_LINK1_BASE, .size = SZ_4K}, + + /* DSI2 link registers */ + {.base = U8500_DSI_LINK2_BASE, .size = SZ_4K}, + + /* DSI3 link registers */ + {.base = U8500_DSI_LINK3_BASE, .size = SZ_4K}, + + /* DMA Ctrl. configuration registers (base address changed in V1) */ + {.base = U8500_DMA_BASE, .size = SZ_4K}, + + /* 0xB7A00000 -> 0xB7E04000: Modem I2C */ + {.base = U8500_MODEM_I2C, .size = 0x404000}, + + /* 0xA0390000 -> 0xA039FFFF: SBAG configuration registers */ + {.base = U8500_SBAG_BASE, .size = SZ_4K}, + + /* 0xA0300000 -> 0xA031FFFF: SGA configuration registers */ + {.base = U8500_SGA_BASE, .size = 0x10000}, + + /* 0xA0200000 -> 0xA02FFFFF: Smart Imaging Acc. Data Memory space (SIA) */ + {.base = U8500_SIA_BASE, .size = 0x60000}, + + /* 0xA0100000 -> 0xA01FFFFF: Smart Video Acc. Data Memory space (SVA) */ + {.base = U8500_SVA_BASE, .size = 0x60000}, + + /* 0x81000000 -> 0x8103FFFF: Main ICN Crossbar configuration registers */ + {.base = U8500_ICN_BASE, .size = 0x2000}, + + /* 0x80140000 -> 0x8014FFFF: HSEM (Semaphores) configuration */ + {.base = U8500_HSEM_BASE, .size = SZ_4K}, + + /* 0x80130000 -> 0x8013FFFF: B2R2 configuration registers */ + {.base = U8500_B2R2_BASE, .size = SZ_4K}, + + /* 0x80100000 -> 0x8010FFFF: STM */ + {.base = U8500_STM_BASE, .size = 0x10000}, + + /* High part of embedded boot ROM */ + {.base = U8500_ASIC_ID_BASE, .size = SZ_4K}, + + /* 0x17C4 0000 : 0x17C4 007C */ + {.base = U8500_SCU_CD_R4_BASE, .size = SZ_4K}, + + /* 0x17D4 0000 : 0x17D4 041C */ + {.base = U8500_SCU_AD_R4_BASE, .size = SZ_4K}, + + /* 0x17E0 2000 : 0x17E0 2FFC */ + {.base = U8500_HSI2CMODEMR4_BASE, .size = SZ_4K}, + + {.base = 0, .size = 0, }, + +}; + +static void hwreg_io_init(void) +{ + int i; + + for (i = 0; hwreg_io_map[i].base; ++i) { + hwreg_io_map[i].addr = ioremap(hwreg_io_map[i].base, + hwreg_io_map[i].size); + if (!hwreg_io_map[i].addr) + printk(KERN_WARNING + "%s: ioremap for %d (%08x) failed\n", + __func__, i, hwreg_io_map[i].base); + } +} + +static void hwreg_io_exit(void) +{ + int i; + + for (i = 0; hwreg_io_map[i].base; ++i) + if (hwreg_io_map[i].addr) + iounmap(hwreg_io_map[i].addr); +} + +static void *hwreg_io_ptov(u32 phys) +{ + int i; + + for (i = 0; hwreg_io_map[i].base; ++i) { + u32 base = hwreg_io_map[i].base; + u32 size = hwreg_io_map[i].size; + u8 *addr = hwreg_io_map[i].addr; + + if (phys < base || phys >= base + size) + continue; + + if (addr) + return addr + phys - base; + + break; + } + + return NULL; +} + + +/* + * HWREG 32bit DB8500 register read/write access debugfs part + */ + +static int hwreg_address_print(struct seq_file *s, void *p) +{ + return seq_printf(s, "0x%08X\n", debug_address); +} + +static int hwreg_address_open(struct inode *inode, struct file *file) +{ + return single_open(file, hwreg_address_print, inode->i_private); +} + +static ssize_t hwreg_address_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[32]; + int buf_size; + unsigned long user_address; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if(strict_strtoul(buf, 0, &user_address)) + return -EINVAL; + if (hwreg_io_ptov(user_address)==NULL) + return -EADDRNOTAVAIL; + + debug_address = user_address; + return buf_size; +} + +static int hwreg_value_print(struct seq_file *s, void *p) +{ + void *ptr; + + ptr = hwreg_io_ptov(debug_address); + if (ptr == NULL) + return -EADDRNOTAVAIL; + seq_printf(s, "0x%X\n", readl(ptr)); + return 0; +} + +static int hwreg_value_open(struct inode *inode, struct file *file) +{ + return single_open(file, hwreg_value_print, inode->i_private); +} + +static ssize_t hwreg_value_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[32]; + int buf_size; + unsigned long user_val; + void *ptr; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (strict_strtoul(buf, 0, &user_val)) + return -EINVAL; + + if ((ptr = hwreg_io_ptov(debug_address)) == NULL) + return -EFAULT; + writel(user_val, ptr); + return buf_size; +} + +static const struct file_operations hwreg_address_fops = { + .open = hwreg_address_open, + .write = hwreg_address_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; +static const struct file_operations hwreg_value_fops = { + .open = hwreg_value_open, + .write = hwreg_value_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +/* 'map' read entry: display current HWREG IO mapping table */ +static int hwreg_map_print(struct seq_file *s, void *p) +{ + int err, i; + for (i = 0; hwreg_io_map[i].base; ++i) { + err = seq_printf(s, "%d: 0x%08X => 0x%08X\n", + i, hwreg_io_map[i].base, + hwreg_io_map[i].base+hwreg_io_map[i].size); + if (err < 0) + return -ENOMEM; + } + return 0; +} +static int hwreg_map_open(struct inode *inode, struct file *file) +{ + return single_open(file, hwreg_map_print, inode->i_private); +} + +static const struct file_operations hwreg_map_fops = { + .open = hwreg_map_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +/* + * HWREG DB8500 formated routines + */ + +static int hwreg_print(struct seq_file *s, void *d) +{ + struct hwreg_cfg *c = (struct hwreg_cfg*) s->private; + void *p; + uint v; + + if ((c==NULL) || ((p = hwreg_io_ptov(c->addr))==NULL)) + return -EADDRNOTAVAIL; + + v = (uint) (REG_FMT_32B(c) ? readl(p) : REG_FMT_16B(c) ? readw(p) : readb(p)); + v = (c->shift>=0) ? v >> c->shift : v << (-c->shift); + v = v & c->mask; + + if (REG_FMT_DEC(c)) + seq_printf(s, "%d\n", v); + else if (REG_FMT_32B(c)) + seq_printf(s, "0x%08X\n", v); + else if (REG_FMT_32B(c)) + seq_printf(s, "0x%04X\n", v); + else + seq_printf(s, "0x%02X\n", v); + return 0; +} + +static int hwreg_open(struct inode *inode, struct file *file) +{ + return single_open(file, hwreg_print, inode->i_private); +} + +/* + * return length of an ASCII numerical value, 0 is string is not a numerical + * value. string shall start at value 1st char. + * string can be tailed with \0 or space or newline chars only. + * value can be decimal or hexadecimal (prefixed 0x or 0X). + */ +static int strval_len(char *b) +{ + char *s = b; + if((*s=='0') && ((*(s+1)=='x') || (*(s+1)=='X'))) { + s += 2; + for (; *s && (*s!=' ') && (*s!='\n'); s++) { + if (!isxdigit(*s)) + return 0; + } + } else { + if (*s=='-') + s++; + for (; *s && (*s!=' ') && (*s!='\n'); s++) { + if (!isdigit(*s)) + return 0; + } + } + return (int) (s-b); +} + +/* + * parse hwreg input data. + * update global hwreg_cfg only if input data syntax is ok. + */ +static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg) +{ + uint write, val=0, offset=0; + struct hwreg_cfg loc = { + .addr = 0, /* default: invalid phys addr */ + .fmt = 0, /* default: 32bit access, hex output */ + .mask = 0xFFFFFFFF, /* default: no mask */ + .shift = 0, /* default: no bit shift */ + }; + + /* read or write ? */ + if(!strncmp(b, "read ", 5)) { + write = 0; + b += 5; + } else if (!strncmp(b, "write ", 6)) { + write = 1; + b += 6; + } else { + return -EINVAL; + } + + /* OPTIONS -l|-w|-b -s -m -o */ + while((*b==' ') || (*b=='-')) { + if (*(b-1)!=' ') { + b++; + continue; + } + if ((!strncmp(b, "-d ", 3)) || (!strncmp(b, "-dec ", 5))) { + b += (*(b+2)==' ') ? 3 : 5; + loc.fmt |= (1<<0); + } else if ((!strncmp(b, "-h ", 3)) || (!strncmp(b, "-hex ", 5))) { + b += (*(b+2)==' ') ? 3 : 5; + loc.fmt &= ~(1<<0); + } else if ((!strncmp(b, "-m ", 3)) || (!strncmp(b, "-mask ", 6))) { + b += (*(b+2)==' ') ? 3 : 6; + if (strval_len(b)==0) + return -EINVAL; + loc.mask = simple_strtoul(b, &b, 0); + } else if ((!strncmp(b, "-s ", 3)) || (!strncmp(b,"-shift ", 7))) { + b += (*(b+2)==' ') ? 3 : 7; + if (strval_len(b)==0) + return -EINVAL; + loc.shift = simple_strtol(b, &b, 0); + + } else if ((!strncmp(b, "-o ", 3)) || (!strncmp(b,"-offset ", 8))) { + b += (*(b+2)==' ') ? 3 : 8; + if (strval_len(b)==0) + return -EINVAL; + offset = simple_strtol(b, &b, 0); + } else if (!strncmp(b, "-l ", 3)) { + b += 3; + loc.fmt = (loc.fmt & ~(3<<1)) | (0<<1); + } else if (!strncmp(b, "-w ", 3)) { + b += 3; + loc.fmt = (loc.fmt & ~(3<<1)) | (1<<1); + } else if (!strncmp(b, "-b ", 3)) { + b += 3; + loc.fmt = (loc.fmt & ~(3<<1)) | (2<<1); + } else { + return -EINVAL; + } + } + /* get arg ADDRESS */ + if (strval_len(b)==0) + return -EINVAL; + loc.addr = simple_strtoul(b, &b, 0); + loc.addr += offset; + if (hwreg_io_ptov(loc.addr) == NULL) + return -EINVAL; + + if (write) { + while(*b==' ') b++; /* skip spaces up to arg VALUE */ + if (strval_len(b)==0) + return -EINVAL; + val = simple_strtoul(b, &b, 0); + } + + /* args are ok, update target cfg (mainly for read) */ + *cfg = loc; + +#ifdef DEBUG + printk(KERN_INFO "HWREG request: %s %d-bit reg, %s, addr=0x%08X, " + "mask=0x%X, shift=%d value=0x%X\n", + (write)?"write":"read", + REG_FMT_32B(cfg)?32:REG_FMT_16B(cfg)?16:8, + REG_FMT_DEC(cfg)?"decimal":"hexa", + cfg->addr, cfg->mask, cfg->shift, val); +#endif + + if (write) { + void *p = hwreg_io_ptov(cfg->addr); + uint d = (uint) (REG_FMT_32B(cfg)) ? readl(p) : + (REG_FMT_16B(cfg)) ? readw(p) : readb(p); + + if (cfg->shift>=0) { + d &= ~(cfg->mask << (cfg->shift)); + val = (val & cfg->mask) << (cfg->shift); + } else { + d &= ~(cfg->mask >> (-cfg->shift)); + val = (val & cfg->mask) >> (-cfg->shift); + } + val = val | d; + + /* read reg, reset mask field and update value bit-field */ + if (REG_FMT_32B(cfg)) + writel(val, p); + else if (REG_FMT_16B(cfg)) + writew(val, p); + else + writeb(val, p); + } + return 0; +} + +static ssize_t hwreg_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buf[128]; + int buf_size, ret; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* get args and process */ + ret = hwreg_common_write(buf, &hwreg_cfg); + return (ret) ? ret : buf_size; +} + +static const struct file_operations hwreg_fops = { + .open = hwreg_open, + .write = hwreg_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +/* + * hwreg module init/cleanup + */ +static int __init hwreg_initialize(void) +{ + static struct dentry *file; + hwreg_io_init(); + + hwreg_debugfs_dir = debugfs_create_dir("mem", NULL); + if (!hwreg_debugfs_dir) + goto debugfs_err; + + file = debugfs_create_file("reg-addr", + (S_IRUGO | S_IWUGO), hwreg_debugfs_dir, + NULL, &hwreg_address_fops); + if (!file) + goto debugfs_err; + file = debugfs_create_file("reg-val", + (S_IRUGO | S_IWUGO), hwreg_debugfs_dir, + NULL, &hwreg_value_fops); + if (!file) + goto debugfs_err; + file = debugfs_create_file("reg-map", + (S_IRUGO), + hwreg_debugfs_dir, NULL, &hwreg_map_fops); + if (!file) + goto debugfs_err; + file = debugfs_create_file("hwreg", + (S_IRUGO), + hwreg_debugfs_dir, &hwreg_cfg, &hwreg_fops); + if (!file) + goto debugfs_err; + return 0; + +debugfs_err: + if (hwreg_debugfs_dir) + debugfs_remove_recursive(hwreg_debugfs_dir); + printk(KERN_ERR "hwreg: failed to register debugfs entries.\n"); + return -1; +} + +static void __exit hwreg_finalize(void) +{ + debugfs_remove_recursive(hwreg_debugfs_dir); + hwreg_io_exit(); +} + +module_init(hwreg_initialize); +module_exit(hwreg_finalize); + +MODULE_AUTHOR("ST-Ericsson"); +MODULE_DESCRIPTION("DB8500 HW registers access through debugfs"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From bc52cfb0c0aebaed24dab77b33477a20d4e0a430 Mon Sep 17 00:00:00 2001 From: Jonas Aaberg Date: Wed, 30 Jun 2010 14:00:40 +0200 Subject: Boottime - A tool for automatic measurement of kernel and possible boot loader boot time. The overhead is very low and the results will be found under sysfs/bootime, as well as detailed results in debugfs under boottime/. The bootgraph* files are compatible with scripts/bootgraph.pl. The reason for this patch is to provide data (sysfs/boottime) suitable for automatic testcases as well as help for developers to reduce the boot time (debugfs). Signed-off-by: Jonas Aaberg Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/2760 Change-Id: Id8ea7226b3f1f783448962195193b90699d32fc6 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/3174 Tested-by: Mian Yousaf KAUKAB Reviewed-by: Srinidhi KASAGAR Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Lee Jones --- arch/arm/common/Makefile | 1 + arch/arm/common/boottime.c | 46 +++++ arch/arm/include/asm/setup.h | 21 ++ include/linux/boottime.h | 89 +++++++++ init/Kconfig | 9 + init/Makefile | 1 + init/boottime.c | 467 +++++++++++++++++++++++++++++++++++++++++++ init/main.c | 6 + 8 files changed, 640 insertions(+) create mode 100644 arch/arm/common/boottime.c create mode 100644 include/linux/boottime.h create mode 100644 init/boottime.c (limited to 'arch') diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 215816f1775..d5b5aa2fe3c 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_ARCH_IXP2000) += uengine.o obj-$(CONFIG_ARCH_IXP23XX) += uengine.o obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o +obj-$(CONFIG_BOOTTIME) += boottime.o diff --git a/arch/arm/common/boottime.c b/arch/arm/common/boottime.c new file mode 100644 index 00000000000..73e9e04ed37 --- /dev/null +++ b/arch/arm/common/boottime.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) ST-Ericsson SA 2009-2010 + * + * Author: Jonas Aaberg for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + * + * Store boot times measured during for example u-boot startup. + */ + +#include +#include +#include +#include +#include + +static u32 bootloader_idle; +static u32 bootloader_total; + +static int __init boottime_parse_tag(const struct tag *tag) +{ + int i; + char buff[BOOTTIME_MAX_NAME_LEN]; + + bootloader_idle = tag->u.boottime.idle; + bootloader_total = tag->u.boottime.total; + + for (i = 0; i < tag->u.boottime.num; i++) { + snprintf(buff, BOOTTIME_MAX_NAME_LEN, "%s+0x0/0x0", + tag->u.boottime.entry[i].name); + buff[BOOTTIME_MAX_NAME_LEN - 1] = '\0'; + boottime_mark_wtime(buff, tag->u.boottime.entry[i].time); + } + + return 0; +} + +__tagtable(ATAG_BOOTTIME, boottime_parse_tag); + +int boottime_bootloader_idle(void) +{ + if (bootloader_total == 0) + return 0; + + return (int) ((bootloader_idle) / (bootloader_total / 100)); +} diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h index 23ebc0c82a3..ea1384fea05 100644 --- a/arch/arm/include/asm/setup.h +++ b/arch/arm/include/asm/setup.h @@ -143,6 +143,23 @@ struct tag_memclk { __u32 fmemclk; }; +/* for automatic boot timing testcases */ +#define ATAG_BOOTTIME 0x41000403 +#define BOOTTIME_MAX_NAME_LEN 64 +#define BOOTTIME_MAX 10 + +struct boottime_entry { + u32 time; /* in us */ + u8 name[BOOTTIME_MAX_NAME_LEN]; +}; + +struct tag_boottime { + struct boottime_entry entry[BOOTTIME_MAX]; + u32 idle; /* in us */ + u32 total; /* in us */ + u8 num; +}; + struct tag { struct tag_header hdr; union { @@ -165,6 +182,10 @@ struct tag { * DC21285 specific */ struct tag_memclk memclk; + /* + * Boot time + */ + struct tag_boottime boottime; } u; }; diff --git a/include/linux/boottime.h b/include/linux/boottime.h new file mode 100644 index 00000000000..9836c5b3175 --- /dev/null +++ b/include/linux/boottime.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) ST-Ericsson SA 2009-2010 + * + * Author: Jonas Aaberg for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + * + * boottime is a tool for collecting start-up timing + * information and can together with boot loader support + * display a total system start-up time. + * + */ + +#ifndef LINUX_BOOTTIME_H +#define LINUX_BOOTTIME_H + +#ifdef CONFIG_BOOTTIME +#include + +/** + * struct boottime_timer - Callbacks for generic timer. + * @init: Function to call at boottime initialization + * @get_time: Returns the number of us since start-up + * Preferable this is based upon a free running timer. + * This is the only required entry. + * @finalize: Called before init is executed and boottime is done. + */ +struct boottime_timer { + int (*init)(void); + unsigned long (*get_time)(void); + void (*finalize)(void); +}; + +/** + * boottime_mark_wtime() + * Add a sample point with a given time. Useful for adding data collected + * by for example a boot loader. + * @name: The name of the sample point + * @time: The time in us when this point was reached + */ +void __init boottime_mark_wtime(char *name, unsigned long time); + +/** + * boottime_mark() + * Add a sample point with the current time. + * @name: The name of this sample point + */ +void __init boottime_mark(char *name); + +/** + * boottime_mark_symbolic() + * Add a sample point where the name is a symbolic function + * and %pF is needed to get the correct function name. + * @name: function name. + */ +void __init boottime_mark_symbolic(void *name); + +/** + * boottime_activate() + * Activates boottime and register callbacks. + * @bt: struct with callbacks. + */ +void __ref boottime_activate(struct boottime_timer *bt); + +/** + * boottime_deactivate() + * This function is called when the kernel boot is done. + * (before "free init memory" is called) + */ +void __init boottime_deactivate(void); + +/** + * boottime_system_up() + * A function is called when the basics of the kernel + * is up and running. + */ +void __init boottime_system_up(void); + +#else + +#define boottime_mark_wtime(name, time) +#define boottime_mark(name) +#define boottime_mark_symbolic(name) +#define boottime_activate(bt) +#define boottime_deactivate() +#define boottime_system_up() +#endif + +#endif /* LINUX_BOOTTIME_H */ diff --git a/init/Kconfig b/init/Kconfig index 6cfd71d0646..c2786394546 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1311,6 +1311,15 @@ config PROFILING Say Y here to enable the extended profiling support mechanisms used by profilers such as OProfile. +config BOOTTIME + bool "Boot time measurments" + default n + help + Adds sysfs entries (boottime/) with start-up timing information. + If CONFIG_DEBUG_FS is enabled, detailed information about the + boot time, including system load during boot can be extraced. + This information can be visualised with help of the bootgraph script. + # # Place an empty function call at each tracepoint site. Can be # dynamically changed for a probe function. diff --git a/init/Makefile b/init/Makefile index 0bf677aa087..6b77be3855f 100644 --- a/init/Makefile +++ b/init/Makefile @@ -9,6 +9,7 @@ else obj-$(CONFIG_BLK_DEV_INITRD) += initramfs.o endif obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o +obj-$(CONFIG_BOOTTIME) += boottime.o mounts-y := do_mounts.o mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o diff --git a/init/boottime.c b/init/boottime.c new file mode 100644 index 00000000000..be73e0ee550 --- /dev/null +++ b/init/boottime.c @@ -0,0 +1,467 @@ +/* + * Copyright (C) ST-Ericsson SA 2009-2010 + * + * Author: Jonas Aaberg for ST-Ericsson + * + * License terms: GNU General Public License (GPL) version 2 + * + * boottime is a tool for collecting start-up timing + * information and can together with boot loader support + * display a total system start-up time. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * BOOTTIME_MAX_NAME_LEN is defined in arch/arm/include/asm/setup.h to 64. + * No crisis if they don't match. + */ +#ifndef BOOTTIME_MAX_NAME_LEN +#define BOOTTIME_MAX_NAME_LEN 64 +#endif + +/* + * We have a few static entries, since it is good to have measure points + * before the system is up and running properly + */ +#define NUM_STATIC_BOOTTIME_ENTRIES 16 + +struct boottime_list { + struct list_head list; + char name[BOOTTIME_MAX_NAME_LEN]; + /* Time in us since power on, possible including boot loader. */ + unsigned long time; + bool cpu_load; + struct cpu_usage_stat cpu_usage[NR_CPUS]; +}; + +enum boottime_filter_type { + BOOTTIME_FILTER_OUT_ZERO, + BOOTTIME_FILTER_OUT_LESS_100, + BOOTTIME_FILTER_NOTHING, +}; + +enum boottime_symbolic_print { + BOOTTIME_SYMBOLIC_PRINT, + BOOTTIME_NORMAL_PRINT, +}; + +enum boottime_cpu_load { + BOOTTIME_CPU_LOAD, + BOOTTIME_NO_CPU_LOAD, +}; + +static LIST_HEAD(boottime_list); +static __initdata DEFINE_SPINLOCK(boottime_list_lock); +static __initdata struct boottime_timer boottime_timer; +static __initdata int num_const_boottime_list; +static struct boottime_list const_boottime_list[NUM_STATIC_BOOTTIME_ENTRIES]; +static unsigned long time_kernel_done; +static unsigned long time_bootloader_done; +static __initdata bool system_up; +static bool boottime_done; + +int __attribute__((weak)) boottime_arch_startup(void) +{ + return 0; +} + +int __attribute__((weak)) boottime_bootloader_idle(void) +{ + return 0; +} + +static void __init boottime_mark_core(char *name, + unsigned long time, + enum boottime_symbolic_print symbolic, + enum boottime_cpu_load cpu_load) +{ + struct boottime_list *b; + unsigned long flags = 0; + int i; + + if (system_up) { + b = kmalloc(sizeof(struct boottime_list), GFP_KERNEL); + if (!b) { + printk(KERN_ERR + "boottime: failed to allocate memory!\n"); + return; + } + + } else { + if (num_const_boottime_list < NUM_STATIC_BOOTTIME_ENTRIES) { + b = &const_boottime_list[num_const_boottime_list]; + num_const_boottime_list++; + } else { + printk(KERN_ERR + "boottime: too many early measure points!\n"); + return; + } + } + + INIT_LIST_HEAD(&b->list); + + if (symbolic == BOOTTIME_SYMBOLIC_PRINT) + snprintf(b->name, BOOTTIME_MAX_NAME_LEN, "%pF", name); + else + strncpy(b->name, name, BOOTTIME_MAX_NAME_LEN); + + b->name[BOOTTIME_MAX_NAME_LEN - 1] = '\0'; + b->time = time; + b->cpu_load = cpu_load; + + if (cpu_load == BOOTTIME_CPU_LOAD && system_up) + for_each_possible_cpu(i) { + b->cpu_usage[i].system = kstat_cpu(i).cpustat.system; + b->cpu_usage[i].idle = kstat_cpu(i).cpustat.idle; + b->cpu_usage[i].iowait = kstat_cpu(i).cpustat.iowait; + b->cpu_usage[i].irq = kstat_cpu(i).cpustat.irq; + /* + * TODO: Make sure that user, nice, softirq, steal + * and guest are not used during boot + */ + } + else + b->cpu_load = BOOTTIME_NO_CPU_LOAD; + + if (system_up) { + spin_lock_irqsave(&boottime_list_lock, flags); + list_add(&b->list, &boottime_list); + spin_unlock_irqrestore(&boottime_list_lock, flags); + } else { + list_add(&b->list, &boottime_list); + } +} + +void __init boottime_mark_wtime(char *name, unsigned long time) +{ + boottime_mark_core(name, time, + BOOTTIME_NORMAL_PRINT, + BOOTTIME_NO_CPU_LOAD); +} + +void __ref boottime_mark_symbolic(void *name) +{ + + if (boottime_done) + return; + + if (boottime_timer.get_time) + boottime_mark_core((char *) name, + boottime_timer.get_time(), + BOOTTIME_SYMBOLIC_PRINT, + BOOTTIME_CPU_LOAD); +} + +void __init boottime_mark(char *name) +{ + if (boottime_timer.get_time) + boottime_mark_core(name, + boottime_timer.get_time(), + BOOTTIME_NORMAL_PRINT, + BOOTTIME_CPU_LOAD); +} + +void __init boottime_activate(struct boottime_timer *bt) +{ + struct boottime_list *b; + int res = 0; + unsigned long flags; + + if (bt == NULL) { + printk(KERN_ERR + "boottime: error: bad configured\n"); + return; + } + + if (bt->get_time == NULL) { + printk(KERN_ERR + "boottime: error: you must provide a get_time() function\n"); + return; + } + memcpy(&boottime_timer, bt, sizeof(struct boottime_timer)); + + if (boottime_timer.init) + res = boottime_timer.init(); + + if (res) { + printk(KERN_ERR "boottime: initialization failed\n"); + return; + } + + if (boottime_arch_startup()) + printk(KERN_ERR + "boottime: arch specfic initialization failed\n"); + + spin_lock_irqsave(&boottime_list_lock, flags); + + if (!list_empty(&boottime_list)) { + + b = list_first_entry(&boottime_list, struct boottime_list, + list); + if (b) + time_bootloader_done = b->time; + } + + spin_unlock_irqrestore(&boottime_list_lock, flags); +} + +void __init boottime_system_up(void) +{ + system_up = true; +} + +void __init boottime_deactivate(void) +{ + struct boottime_list *b; + unsigned long flags; + + boottime_mark("execute_init+0x0/0x0"); + + boottime_done = true; + + spin_lock_irqsave(&boottime_list_lock, flags); + b = list_first_entry(&boottime_list, struct boottime_list, list); + spin_unlock_irqrestore(&boottime_list_lock, flags); + + time_kernel_done = b->time; + + if (boottime_timer.finalize) + boottime_timer.finalize(); +} + +#ifdef CONFIG_DEBUG_FS +static void boottime_debugfs_load(struct seq_file *s, + struct boottime_list *b, + struct boottime_list *p) +{ + int i; + unsigned long total_p, total_b; + unsigned long system_total, idle_total, irq_total, iowait_total; + unsigned long system_load, idle_load, irq_load, iowait_load; + + for_each_possible_cpu(i) { + total_b = (b->cpu_usage[i].system + + b->cpu_usage[i].idle + + b->cpu_usage[i].iowait + + b->cpu_usage[i].irq); + + total_p = (p->cpu_usage[i].system + + p->cpu_usage[i].idle + + p->cpu_usage[i].iowait + + p->cpu_usage[i].irq); + + if (total_b == total_p) + continue; + + system_total = b->cpu_usage[i].system - p->cpu_usage[i].system; + idle_total = b->cpu_usage[i].idle - p->cpu_usage[i].idle; + irq_total = b->cpu_usage[i].irq - p->cpu_usage[i].irq; + iowait_total = b->cpu_usage[i].iowait - p->cpu_usage[i].iowait; + + system_load = (100 * system_total / (total_b - total_p)); + idle_load = (100 * idle_total / (total_b - total_p)); + irq_load = (100 * irq_total / (total_b - total_p)); + iowait_load = (100 * iowait_total / (total_b - total_p)); + + seq_printf(s, + " cpu%d system: %lu%% idle: %lu%% iowait: %lu%% irq: %lu%%", + i, + system_load, + idle_load, + iowait_load, + irq_load); + } + seq_printf(s, "\n"); +} + +static void boottime_debugfs_print(struct seq_file *s, + struct boottime_list *b, + struct boottime_list *p) +{ + seq_printf(s, "[%5lu.%06lu] calling %s\n", + p->time / 1000000, + (p->time % 1000000), + p->name); + seq_printf(s, "[%5lu.%06lu] initcall %s returned 0 after %ld msecs.", + b->time / 1000000, + (b->time % 1000000), + p->name, (b->time - p->time) / 1000); + + if (p->cpu_load == BOOTTIME_NO_CPU_LOAD || + b->cpu_load == BOOTTIME_NO_CPU_LOAD) { + seq_printf(s, "\n"); + return; + } + + boottime_debugfs_load(s, b, p); +} + +static int boottime_debugfs_bootgraph_show(struct seq_file *s, void *iter) +{ + struct boottime_list *b, *p = NULL, *old_p = NULL; + enum boottime_filter_type filter = (int)s->private; + + list_for_each_entry_reverse(b, &boottime_list, list) { + if (p) { + if (!(filter == BOOTTIME_FILTER_OUT_ZERO && + (b->time - p->time) / 1000 == 0) + && !(filter == BOOTTIME_FILTER_OUT_LESS_100 && + (b->time - p->time) < 100 * 1000)) + boottime_debugfs_print(s, b, p); + old_p = p; + } + p = b; + } + + if (filter == BOOTTIME_FILTER_NOTHING && p) + boottime_debugfs_print(s, p, p); + + if (p) + seq_printf(s, "[%5lu.%06lu] Freeing init memory: 0K\n", + p->time / 1000000, p->time % 1000000); + return 0; +} + +static int boottime_debugfs_summary_show(struct seq_file *s, void *data) +{ + struct boottime_list *b, b_zero; + + if (time_bootloader_done) + seq_printf(s, "bootloader: %ld msecs\n", + time_bootloader_done / 1000); + + seq_printf(s, "kernel: %ld msecs\ntotal: %ld msecs\n", + (time_kernel_done - time_bootloader_done) / 1000, + time_kernel_done / 1000); + seq_printf(s, "kernel:"); + b = list_first_entry(&boottime_list, + struct boottime_list, list); + memset(&b_zero, 0, sizeof(struct boottime_list)); + boottime_debugfs_load(s, b, &b_zero); + + if (time_bootloader_done) + seq_printf(s, + "bootloader: cpu0 system: %d%% idle: %d%% iowait: 0%% irq: 0%%\n", + 100 - boottime_bootloader_idle(), + boottime_bootloader_idle()); + return 0; +} + +static int boottime_debugfs_bootgraph_open(struct inode *inode, + struct file *file) +{ + return single_open(file, + boottime_debugfs_bootgraph_show, + inode->i_private); +} + +static int boottime_debugfs_summary_open(struct inode *inode, + struct file *file) +{ + return single_open(file, + boottime_debugfs_summary_show, + inode->i_private); +} + +static const struct file_operations boottime_debugfs_bootgraph_operations = { + .open = boottime_debugfs_bootgraph_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations boottime_debugfs_summary_operations = { + .open = boottime_debugfs_summary_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void boottime_debugfs_init(void) +{ + struct dentry *dir; + + dir = debugfs_create_dir("boottime", NULL); + + (void) debugfs_create_file("bootgraph", S_IFREG | S_IRUGO, + dir, (void *)BOOTTIME_FILTER_NOTHING, + &boottime_debugfs_bootgraph_operations); + (void) debugfs_create_file("bootgraph_all_except0", S_IFREG | S_IRUGO, + dir, (void *)BOOTTIME_FILTER_OUT_ZERO, + &boottime_debugfs_bootgraph_operations); + (void) debugfs_create_file("bootgraph_larger100", + S_IFREG | S_IRUGO, + dir, (void *)BOOTTIME_FILTER_OUT_LESS_100, + &boottime_debugfs_bootgraph_operations); + (void) debugfs_create_file("summary", S_IFREG | S_IRUGO, + dir, NULL, + &boottime_debugfs_summary_operations); +} +#else +#define boottime_debugfs_init(x) +#endif + +static ssize_t show_bootloader(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%ld\n", time_bootloader_done / 1000); +} + +static ssize_t show_kernel(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%ld\n", + (time_kernel_done - time_bootloader_done) / 1000); +} + +DEVICE_ATTR(kernel, 0444, show_kernel, NULL); +DEVICE_ATTR(bootloader, 0444, show_bootloader, NULL); + +static struct attribute *boottime_sysfs_entries[] = { + &dev_attr_kernel.attr, + &dev_attr_bootloader.attr, + NULL +}; + +static struct attribute_group boottime_attr_grp = { + .name = NULL, + .attrs = boottime_sysfs_entries, +}; + +static int __init boottime_init(void) +{ + struct kobject *boottime_kobj; + + boottime_kobj = kobject_create_and_add("boottime", NULL); + if (!boottime_kobj) { + printk(KERN_ERR "boottime: out of memory!\n"); + return -ENOMEM; + } + + if (sysfs_create_group(boottime_kobj, &boottime_attr_grp) < 0) { + kobject_put(boottime_kobj); + printk(KERN_ERR "boottime: Failed creating sysfs group\n"); + return -ENOMEM; + } + + boottime_debugfs_init(); + + return 0; +} + +late_initcall(boottime_init); diff --git a/init/main.c b/init/main.c index 44b2433334c..90c0067c647 100644 --- a/init/main.c +++ b/init/main.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include @@ -678,6 +679,8 @@ int __init_or_module do_one_initcall(initcall_t fn) int count = preempt_count(); int ret; + boottime_mark_symbolic(fn); + if (initcall_debug) ret = do_one_initcall_debug(fn); else @@ -802,6 +805,7 @@ static noinline int init_post(void) { /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); + boottime_deactivate(); free_initmem(); mark_rodata_ro(); system_state = SYSTEM_RUNNING; @@ -857,6 +861,7 @@ static int __init kernel_init(void * unused) do_pre_smp_initcalls(); lockup_detector_init(); + boottime_system_up(); smp_init(); sched_init_smp(); @@ -879,6 +884,7 @@ static int __init kernel_init(void * unused) if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) { ramdisk_execute_command = NULL; + boottime_mark("mount+0x0/0x0"); prepare_namespace(); } -- cgit v1.2.3 From 70994fbb103b0d8d9990669b3d3beb3359e905a9 Mon Sep 17 00:00:00 2001 From: Jonas Aaberg Date: Mon, 20 Jun 2011 12:09:38 +0200 Subject: ARM: ux500: hwreg: Tiny code clean-up ST-Ericsson Linux next: Not tested, ask SSM for ER ST-Ericsson ID: - ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Jonas Aaberg Change-Id: I5b7331fade22ae99dc2600d67b41bf286179cee8 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25489 Reviewed-by: QATEST Reviewed-by: Linus WALLEIJ --- arch/arm/mach-ux500/hwreg.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/hwreg.c b/arch/arm/mach-ux500/hwreg.c index 7ba3e0f2911..1a47e60ed46 100644 --- a/arch/arm/mach-ux500/hwreg.c +++ b/arch/arm/mach-ux500/hwreg.c @@ -300,23 +300,19 @@ static int hwreg_address_open(struct inode *inode, struct file *file) static ssize_t hwreg_address_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - char buf[32]; - int buf_size; + int err; unsigned long user_address; - /* Get userspace string and assure termination */ - buf_size = min(count, (sizeof(buf) - 1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; + err = kstrtoul_from_user(user_buf, count, 0, &user_address); + + if (err) + return err; - if(strict_strtoul(buf, 0, &user_address)) - return -EINVAL; if (hwreg_io_ptov(user_address)==NULL) return -EADDRNOTAVAIL; debug_address = user_address; - return buf_size; + return count; } static int hwreg_value_print(struct seq_file *s, void *p) @@ -338,24 +334,19 @@ static int hwreg_value_open(struct inode *inode, struct file *file) static ssize_t hwreg_value_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - char buf[32]; - int buf_size; + int err; unsigned long user_val; void *ptr; - /* Get userspace string and assure termination */ - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; + err = kstrtoul_from_user(user_buf, count, 0, &user_val); - if (strict_strtoul(buf, 0, &user_val)) - return -EINVAL; + if (err) + return err; if ((ptr = hwreg_io_ptov(debug_address)) == NULL) return -EFAULT; writel(user_val, ptr); - return buf_size; + return count; } static const struct file_operations hwreg_address_fops = { -- cgit v1.2.3 From fb79b11cc32ec8024d8fd34ba412d5d01f0a96e1 Mon Sep 17 00:00:00 2001 From: Jurijs Soloveckis Date: Mon, 3 Oct 2011 15:03:39 +0200 Subject: ARM: u8500: STM: board depended code split Hardware depended code for STM device is moved to the separate file. ST-Ericsson ID: 349677 ST-Ericsson Linux next: N/A ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I5d3d0e069b0e8929b99fcfe9cb5e37a950caf716 Signed-off-by: Jurijs Soloveckis Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32847 Reviewed-by: Pierre PEIFFER Reviewed-by: Sebastian RASMUSSEN Signed-off-by: Robert Marklund --- arch/arm/mach-ux500/board-mop500-stm.c | 203 +++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 arch/arm/mach-ux500/board-mop500-stm.c (limited to 'arch') diff --git a/arch/arm/mach-ux500/board-mop500-stm.c b/arch/arm/mach-ux500/board-mop500-stm.c new file mode 100644 index 00000000000..8a0fc83679d --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-stm.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2011 ST-Ericsson + * + * Author: Pierre Peiffer for ST-Ericsson. + * Author: Olivier Germain + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pins-db8500.h" + +static pin_cfg_t mop500_stm_mipi34_pins[] = { + GPIO70_STMAPE_CLK | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO71_STMAPE_DAT3 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO72_STMAPE_DAT2 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO73_STMAPE_DAT1 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO74_STMAPE_DAT0 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO75_U2_RXD | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO76_U2_TXD | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, +}; + +static pin_cfg_t mop500_stm_mipi60_pins[] = { + GPIO153_U2_RXD, + GPIO154_U2_TXD, + GPIO155_STMAPE_CLK, + GPIO156_STMAPE_DAT3, + GPIO157_STMAPE_DAT2, + GPIO158_STMAPE_DAT1, + GPIO159_STMAPE_DAT0, +}; + +static pin_cfg_t mop500_ske_pins[] = { + GPIO153_KP_I7 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO154_KP_I6 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO155_KP_I5 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO156_KP_I4 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO161_KP_I3 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO162_KP_I2 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO163_KP_I1 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO164_KP_I0 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, + GPIO157_KP_O7 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO158_KP_O6 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO159_KP_O5 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO160_KP_O4 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO165_KP_O3 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO166_KP_O2 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO167_KP_O1 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, + GPIO168_KP_O0 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, +}; + +static int stm_ste_disable_ape_on_mipi60(void) +{ + int retval; + + retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_stm_mipi60_pins)); + if (retval) + pr_err("STM: Failed to disable MIPI60\n"); + else { + retval = nmk_config_pins(ARRAY_AND_SIZE(mop500_ske_pins)); + if (retval) + pr_err("STM: Failed to enable SKE gpio\n"); + } + return retval; +} + +/* + * Manage STM output pins connection (MIP34/MIPI60 connectors) + */ +#define PRCM_GPIOCR (_PRCMU_BASE + 0x138) +#define PRCM_GPIOCR_DBG_STM_MOD_CMD1 0x800 +#define PRCM_GPIOCR_DBG_UARTMOD_CMD0 0x1 + + +static int stm_ste_connection(enum stm_connection_type con_type) +{ + int retval = -EINVAL; + u32 gpiocr = readl(PRCM_GPIOCR); + + if (con_type != STM_DISCONNECT) { + /* Always enable MIPI34 GPIO pins */ + retval = nmk_config_pins( + ARRAY_AND_SIZE(mop500_stm_mipi34_pins)); + if (retval) { + pr_err("STM: Failed to enable MIPI34\n"); + return retval; + } + } + + switch (con_type) { + case STM_DEFAULT_CONNECTION: + case STM_STE_MODEM_ON_MIPI34_NONE_ON_MIPI60: + /* Enable altC3 on GPIO70-74 (STMMOD) & GPIO75-76 (UARTMOD) */ + gpiocr |= (PRCM_GPIOCR_DBG_STM_MOD_CMD1 + | PRCM_GPIOCR_DBG_UARTMOD_CMD0); + writel(gpiocr, PRCM_GPIOCR); + retval = stm_ste_disable_ape_on_mipi60(); + break; + + case STM_STE_APE_ON_MIPI34_NONE_ON_MIPI60: + /* Disable altC3 on GPIO70-74 (STMMOD) & GPIO75-76 (UARTMOD) */ + gpiocr &= ~(PRCM_GPIOCR_DBG_STM_MOD_CMD1 + | PRCM_GPIOCR_DBG_UARTMOD_CMD0); + writel(gpiocr, PRCM_GPIOCR); + retval = stm_ste_disable_ape_on_mipi60(); + break; + + case STM_STE_MODEM_ON_MIPI34_APE_ON_MIPI60: + /* Enable altC3 on GPIO70-74 (STMMOD) and GPIO75-76 (UARTMOD) */ + gpiocr |= (PRCM_GPIOCR_DBG_STM_MOD_CMD1 + | PRCM_GPIOCR_DBG_UARTMOD_CMD0); + writel(gpiocr, PRCM_GPIOCR); + + /* Enable APE on MIPI60 */ + retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_ske_pins)); + if (retval) + pr_err("STM: Failed to disable SKE GPIO\n"); + else { + retval = nmk_config_pins( + ARRAY_AND_SIZE(mop500_stm_mipi60_pins)); + if (retval) + pr_err("STM: Failed to enable MIPI60\n"); + } + break; + + case STM_DISCONNECT: + retval = nmk_config_pins_sleep( + ARRAY_AND_SIZE(mop500_stm_mipi34_pins)); + if (retval) + pr_err("STM: Failed to disable MIPI34\n"); + + retval = stm_ste_disable_ape_on_mipi60(); + break; + + default: + pr_err("STM: bad connection type\n"); + break; + } + return retval; +} + +/* Possible STM sources (masters) on ux500 */ +enum stm_master { + STM_ARM0 = 0, + STM_ARM1 = 1, + STM_SVA = 2, + STM_SIA = 3, + STM_SIA_XP70 = 4, + STM_PRCMU = 5, + STM_MCSBAG = 9 +}; + +#define STM_ENABLE_ARM0 BIT(STM_ARM0) +#define STM_ENABLE_ARM1 BIT(STM_ARM1) +#define STM_ENABLE_SVA BIT(STM_SVA) +#define STM_ENABLE_SIA BIT(STM_SIA) +#define STM_ENABLE_SIA_XP70 BIT(STM_SIA_XP70) +#define STM_ENABLE_PRCMU BIT(STM_PRCMU) +#define STM_ENABLE_MCSBAG BIT(STM_MCSBAG) + +/* + * These are the channels used by NMF and some external softwares + * expect the NMF traces to be output on these channels + * For legacy reason, we need to reserve them. + */ +static const s16 stm_channels_reserved[] = { + 100, /* NMF MPCEE channel */ + 101, /* NMF CM channel */ + 151, /* NMF HOSTEE channel */ +}; + +/* On Ux500 we 2 consecutive STMs therefore 512 channels available */ +static struct stm_platform_data stm_pdata = { + .regs_phys_base = U8500_STM_REG_BASE, + .channels_phys_base = U8500_STM_BASE, + .id_mask = 0x000fffff, /* Ignore revisions differences */ + .channels_reserved = stm_channels_reserved, + .channels_reserved_sz = ARRAY_SIZE(stm_channels_reserved), + /* Enable all except MCSBAG */ + .masters_enabled = STM_ENABLE_ARM0 | STM_ENABLE_ARM1 | + STM_ENABLE_SVA | STM_ENABLE_PRCMU | + STM_ENABLE_SIA | STM_ENABLE_SIA_XP70, + /* Provide function for MIPI34/MIPI60 STM connection */ + .stm_connection = stm_ste_connection, +}; + +struct platform_device u8500_stm_device = { + .name = "stm", + .id = -1, + .dev = { + .platform_data = &stm_pdata, + }, +}; -- cgit v1.2.3 From 5dce3732e65887c11f439e954cbf3afcd9356bbf Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Fri, 18 Nov 2011 15:06:56 +0100 Subject: mach-ux500: STM: break bad dependency with hsi Signed-off-by: Philippe Langlais --- arch/arm/mach-ux500/board-mop500-stm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/board-mop500-stm.c b/arch/arm/mach-ux500/board-mop500-stm.c index 8a0fc83679d..7d8148c5878 100644 --- a/arch/arm/mach-ux500/board-mop500-stm.c +++ b/arch/arm/mach-ux500/board-mop500-stm.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include "pins-db8500.h" -- cgit v1.2.3 From 22e8d8ce6d22656af59b4324a99bd6735de7f613 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Wed, 11 Jan 2012 10:37:58 +0100 Subject: mach-ux500: stm: u8500: API for PRCMU_GPIOCR register The PRCMU_GPIOCR register modification within STM driver is implemented via corresponding API functions. ST-Ericsson ID: 349677 ST-Ericsson Linux next: N/A ST-Ericsson FOSS-OUT ID: Trivial Signed-off-by: Jurijs Soloveckis --- arch/arm/mach-ux500/board-mop500-stm.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/board-mop500-stm.c b/arch/arm/mach-ux500/board-mop500-stm.c index 7d8148c5878..20d3f9a546b 100644 --- a/arch/arm/mach-ux500/board-mop500-stm.c +++ b/arch/arm/mach-ux500/board-mop500-stm.c @@ -77,15 +77,9 @@ static int stm_ste_disable_ape_on_mipi60(void) /* * Manage STM output pins connection (MIP34/MIPI60 connectors) */ -#define PRCM_GPIOCR (_PRCMU_BASE + 0x138) -#define PRCM_GPIOCR_DBG_STM_MOD_CMD1 0x800 -#define PRCM_GPIOCR_DBG_UARTMOD_CMD0 0x1 - - static int stm_ste_connection(enum stm_connection_type con_type) { int retval = -EINVAL; - u32 gpiocr = readl(PRCM_GPIOCR); if (con_type != STM_DISCONNECT) { /* Always enable MIPI34 GPIO pins */ @@ -101,26 +95,19 @@ static int stm_ste_connection(enum stm_connection_type con_type) case STM_DEFAULT_CONNECTION: case STM_STE_MODEM_ON_MIPI34_NONE_ON_MIPI60: /* Enable altC3 on GPIO70-74 (STMMOD) & GPIO75-76 (UARTMOD) */ - gpiocr |= (PRCM_GPIOCR_DBG_STM_MOD_CMD1 - | PRCM_GPIOCR_DBG_UARTMOD_CMD0); - writel(gpiocr, PRCM_GPIOCR); + prcmu_enable_stm_mod_uart(); retval = stm_ste_disable_ape_on_mipi60(); break; case STM_STE_APE_ON_MIPI34_NONE_ON_MIPI60: /* Disable altC3 on GPIO70-74 (STMMOD) & GPIO75-76 (UARTMOD) */ - gpiocr &= ~(PRCM_GPIOCR_DBG_STM_MOD_CMD1 - | PRCM_GPIOCR_DBG_UARTMOD_CMD0); - writel(gpiocr, PRCM_GPIOCR); + prcmu_disable_stm_mod_uart(); retval = stm_ste_disable_ape_on_mipi60(); break; case STM_STE_MODEM_ON_MIPI34_APE_ON_MIPI60: /* Enable altC3 on GPIO70-74 (STMMOD) and GPIO75-76 (UARTMOD) */ - gpiocr |= (PRCM_GPIOCR_DBG_STM_MOD_CMD1 - | PRCM_GPIOCR_DBG_UARTMOD_CMD0); - writel(gpiocr, PRCM_GPIOCR); - + prcmu_enable_stm_mod_uart(); /* Enable APE on MIPI60 */ retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_ske_pins)); if (retval) -- cgit v1.2.3 From 8d9b2a925c726ad702580ced887eeb4f41f37370 Mon Sep 17 00:00:00 2001 From: Jurijs Soloveckis Date: Mon, 17 Oct 2011 10:21:00 +0200 Subject: ARM: u8500: Add control for modem and ape trace SD-card, mipi34 and mipi60 IFs can be configured for modem or ape trace, using u-boot cmd prompt. STM drv is controlled via kernel environment vars: Example: stm.microsd=[none|modem|ape], or stm.mipi34=[none|modem|ape], or stm.mipi60=[none|modem|ape] If trace set to ape, use stm.stm_ter=N to init STM_TER reg with decimal value N (default: N=0). ST-Ericsson ID: 349677 ST-Ericsson Linux next: N/A ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ie04e4c004417c4542259e3074f1fa2fd4f00ce6d Depends-On: I7bbcf263b83338d7b05413dd9dc0ac2ec4880601 Signed-off-by: Jurijs Soloveckis Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/34160 Reviewed-by: QATOOLS Reviewed-by: Jonas ABERG --- arch/arm/mach-ux500/board-mop500-regulators.c | 1 + arch/arm/mach-ux500/board-mop500-stm.c | 277 ++++++++++++++++++++++++-- drivers/misc/stm.c | 60 +++++- include/trace/stm.h | 5 +- 4 files changed, 326 insertions(+), 17 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index 52426a42578..df34f6be694 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -63,6 +63,7 @@ static struct regulator_consumer_supply ab8500_vaux2_consumers[] = { }; static struct regulator_consumer_supply ab8500_vaux3_consumers[] = { + REGULATOR_SUPPLY("v-SD-STM", "stm"), /* External MMC slot power */ REGULATOR_SUPPLY("vmmc", "sdi0"), }; diff --git a/arch/arm/mach-ux500/board-mop500-stm.c b/arch/arm/mach-ux500/board-mop500-stm.c index 20d3f9a546b..d38595b11b2 100644 --- a/arch/arm/mach-ux500/board-mop500-stm.c +++ b/arch/arm/mach-ux500/board-mop500-stm.c @@ -13,13 +13,27 @@ #include #include #include +#include +#include + +#include #include #include -#include #include #include #include "pins-db8500.h" +#define HREFV60_SDMMC_EN_GPIO 169 +#define HREFV60_SDMMC_1V8_3V_GPIO 5 + +#define STM_DEVICE (&u8500_stm_device.dev) +#define STM_ERR(msg) dev_err(STM_DEVICE, msg) +#define STM_WARN(msg) dev_warn(STM_DEVICE, msg) + +static struct regulator *regulator_aux3; +static enum stm_connection_type + stm_current_connection = STM_STE_INVALID_CONNECTION; + static pin_cfg_t mop500_stm_mipi34_pins[] = { GPIO70_STMAPE_CLK | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, GPIO71_STMAPE_DAT3 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, @@ -40,6 +54,15 @@ static pin_cfg_t mop500_stm_mipi60_pins[] = { GPIO159_STMAPE_DAT0, }; +static pin_cfg_t mop500_stm_ape_microsd_pins[] = { + GPIO23_MS_CLK | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO24_MS_BS | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO25_MS_DAT0 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO26_MS_DAT1 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO27_MS_DAT2 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO28_MS_DAT3 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, +}; + static pin_cfg_t mop500_ske_pins[] = { GPIO153_KP_I7 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, GPIO154_KP_I6 | PIN_INPUT_PULLDOWN | PIN_SLPM_INPUT_PULLUP, @@ -59,35 +82,211 @@ static pin_cfg_t mop500_ske_pins[] = { GPIO168_KP_O0 | PIN_INPUT_PULLUP | PIN_SLPM_OUTPUT_LOW, }; +static pin_cfg_t mop500_stm_modem_microsd_pins[] = { + GPIO18_GPIO | PIN_OUTPUT_LOW, + GPIO19_GPIO | PIN_OUTPUT_HIGH, + GPIO20_GPIO | PIN_OUTPUT_HIGH, + GPIO22_GPIO | PIN_INPUT_PULLUP, + GPIO23_STMMOD_CLK | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO24_UARTMOD_RXD | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO25_STMMOD_DAT0 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO26_STMMOD_DAT1 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO27_STMMOD_DAT2 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, + GPIO28_STMMOD_DAT3 | PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP, +}; + +/* sdi0 (removable MMC/SD/SDIO cards) */ +static pin_cfg_t mop500_sdi0_pins[] = { + GPIO18_MC0_CMDDIR | PIN_OUTPUT_HIGH, + GPIO19_MC0_DAT0DIR | PIN_OUTPUT_HIGH, + GPIO20_MC0_DAT2DIR | PIN_OUTPUT_HIGH, + + GPIO22_MC0_FBCLK | PIN_INPUT_NOPULL, + GPIO23_MC0_CLK | PIN_OUTPUT_LOW, + GPIO24_MC0_CMD | PIN_INPUT_PULLUP, + GPIO25_MC0_DAT0 | PIN_INPUT_PULLUP, + GPIO26_MC0_DAT1 | PIN_INPUT_PULLUP, + GPIO27_MC0_DAT2 | PIN_INPUT_PULLUP, + GPIO28_MC0_DAT3 | PIN_INPUT_PULLUP, +}; + static int stm_ste_disable_ape_on_mipi60(void) { int retval; retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_stm_mipi60_pins)); if (retval) - pr_err("STM: Failed to disable MIPI60\n"); + STM_ERR("Failed to disable MIPI60\n"); else { retval = nmk_config_pins(ARRAY_AND_SIZE(mop500_ske_pins)); if (retval) - pr_err("STM: Failed to enable SKE gpio\n"); + STM_ERR("Failed to enable SKE gpio\n"); } return retval; } -/* - * Manage STM output pins connection (MIP34/MIPI60 connectors) - */ +static int stm_enable_ape_microsd(void) +{ + int retval; + + /* + * Configure STM APE on GPIO23,GPIO28,GPIO27,GPIO26,GPIO25 + * On HREF board an external SD buffer exist (ST6G3244ME) + * to perform level conversion from 1.8v to 3.3V on SD card signals + * When STM is redirected on micro SD connector GPIO18,GP19,GPIO20 + * are configured in standard GPIO mode and are used to configure + * direction on external SD buffer ST6G3244ME. + */ + + retval = nmk_config_pins(ARRAY_AND_SIZE(mop500_stm_ape_microsd_pins)); + if (retval) + STM_ERR("Failed to enable STM APE on MICRO SD\n"); + + /* Enable altC1 on GPIO23-28 (STMAPE) */ + prcmu_enable_stm_ape(); + + return retval; +} + +static int stm_disable_ape_microsd(void) +{ + int retval; + + /* Disable altC1 on GPIO23-28 (STMAPE) */ + prcmu_disable_stm_ape(); + + /* Reconfigure GPIO for SD */ + retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_sdi0_pins)); + if (retval) + STM_ERR("Failed to disable STM APE on MICRO SD " + "and to reconfigure GPIO for SD\n"); + + return retval; +} + +static int stm_enable_modem_microsd(void) +{ + int retval; + + /* + * Configure STM APE on GPIO23,GPIO28,GPIO27,GPIO26,GPIO25 + * On HREF board an external SD buffer exist (ST6G3244ME) + * to perform level conversion from 1.8v to 3.3V on SD card + * signals. When STM is redirected on micro SD connector + * GPIO18,GP19,GPIO20 are configured in standard GPIO mode + * and are used to configure direction on external SD buffer + * ST6G3244ME. + */ + + retval = nmk_config_pins(ARRAY_AND_SIZE(mop500_stm_modem_microsd_pins)); + if (retval) + STM_ERR("Failed to enable STM MODEM on MICRO SD\n"); + + return retval; +} + +static int stm_disable_modem_microsd(void) +{ + int retval; + + /* Reconfigure GPIO for SD */ + retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_sdi0_pins)); + if (retval) + STM_ERR("Failed to disable STM MODEM on MICRO SD " + "and to reconfigure GPIO for SD\n"); + + return retval; +} + +/* Enable or disable micro sd card buffers on HREF */ +static void control_level_shifter_for_microsd(int gpio_dir) +{ + int gpio[2]; + + if (machine_is_hrefv60()) { + gpio[0] = HREFV60_SDMMC_EN_GPIO; + gpio[1] = HREFV60_SDMMC_1V8_3V_GPIO; + } else { + gpio[0] = MOP500_EGPIO(17); + gpio[1] = MOP500_EGPIO(18); + } + + /* Select the default 2.9V and enable / disable level shifter */ + gpio_direction_output(gpio[1], 0); + gpio_direction_output(gpio[0], gpio_dir); +} + +/* Enable micro sd card buffers on HREF */ +static int enable_level_shifter_for_microsd(void) +{ + control_level_shifter_for_microsd(1); + STM_WARN("Level Shifter for SD card connector on.\n"); + return 0; +} + +/* Disable micro sd card buffers on HREF */ +static int disable_level_shifter_for_microsd(void) +{ + control_level_shifter_for_microsd(0); + STM_WARN("Level Shifter for SD card connector off.\n"); + return 0; +} + +/* Enable VAUX3 to power on buffer on STM MICRO SD cable */ +static int enable_vaux3_for_microsd_cable(void) +{ + int error; + + regulator_aux3 = regulator_get(&u8500_stm_device.dev, "v-SD-STM"); + + if (IS_ERR(regulator_aux3)) { + error = PTR_ERR(regulator_aux3); + STM_ERR("Failed to get regulator, supply: v-SD-STM\n"); + return error; + } + + error = regulator_enable(regulator_aux3); + + if (error) { + STM_ERR("Unable to enable regulator on SD card connector\n"); + return error; + } + + STM_WARN("Regulator on SD card connector power on.\n"); + return error; +} + +/* Disable VAUX3 to power off buffer on STM MICRO SD cable */ +static int disable_vaux3_for_microsd_cable(void) +{ + int error = 0; + + error = regulator_disable(regulator_aux3); + + if (regulator_aux3) + regulator_put(regulator_aux3); + + STM_WARN("Regulator for stm on SD card connector power off.\n"); + + return error; + +} + static int stm_ste_connection(enum stm_connection_type con_type) { int retval = -EINVAL; + /* Check if connection type has been changed */ + if (con_type == stm_current_connection) + return 0; + if (con_type != STM_DISCONNECT) { /* Always enable MIPI34 GPIO pins */ retval = nmk_config_pins( ARRAY_AND_SIZE(mop500_stm_mipi34_pins)); if (retval) { - pr_err("STM: Failed to enable MIPI34\n"); - return retval; + STM_ERR("Failed to enable MIPI34\n"); + goto stm_ste_connection_error; } } @@ -111,12 +310,40 @@ static int stm_ste_connection(enum stm_connection_type con_type) /* Enable APE on MIPI60 */ retval = nmk_config_pins_sleep(ARRAY_AND_SIZE(mop500_ske_pins)); if (retval) - pr_err("STM: Failed to disable SKE GPIO\n"); + STM_ERR("Failed to disable SKE GPIO\n"); else { retval = nmk_config_pins( ARRAY_AND_SIZE(mop500_stm_mipi60_pins)); if (retval) - pr_err("STM: Failed to enable MIPI60\n"); + STM_ERR("Failed to enable MIPI60\n"); + } + break; + + case STM_STE_MODEM_ON_MICROSD: + /* Disable APE on micro SD */ + retval = stm_disable_ape_microsd(); + /* Enable modem on micro SD */ + if (!retval) + retval = stm_enable_modem_microsd(); + /* Enable SD card buffer and regulator on href */ + if (!retval && (stm_current_connection + != STM_STE_APE_ON_MICROSD)) { + enable_level_shifter_for_microsd(); + enable_vaux3_for_microsd_cable(); + } + break; + + case STM_STE_APE_ON_MICROSD: + /* Disable modem on micro SD */ + retval = stm_disable_modem_microsd(); + /* Enable ape on micro SD */ + if (!retval) + retval = stm_enable_ape_microsd(); + /* Enable SD card buffer and regulator on href */ + if (!retval && (stm_current_connection + != STM_STE_MODEM_ON_MICROSD)) { + enable_level_shifter_for_microsd(); + enable_vaux3_for_microsd_cable(); } break; @@ -124,15 +351,39 @@ static int stm_ste_connection(enum stm_connection_type con_type) retval = nmk_config_pins_sleep( ARRAY_AND_SIZE(mop500_stm_mipi34_pins)); if (retval) - pr_err("STM: Failed to disable MIPI34\n"); + STM_ERR("Failed to disable MIPI34\n"); retval = stm_ste_disable_ape_on_mipi60(); + if (retval) + STM_ERR("Failed to disable MIPI60\n"); + + retval = stm_disable_modem_microsd(); + if (retval) + STM_ERR("Failed to disable modem on microsd\n"); + + retval = stm_disable_ape_microsd(); + if (retval) + STM_ERR("Failed to disable ape on microsd\n"); break; default: - pr_err("STM: bad connection type\n"); - break; + STM_ERR("Bad connection type\n"); + goto stm_ste_connection_error; + } + + /* Disable power for microsd */ + if ((stm_current_connection == STM_STE_MODEM_ON_MICROSD) + || (stm_current_connection == STM_STE_APE_ON_MICROSD)) { + if ((con_type != STM_STE_MODEM_ON_MICROSD) + && (con_type != STM_STE_APE_ON_MICROSD)) { + disable_vaux3_for_microsd_cable(); + disable_level_shifter_for_microsd(); + } } + + stm_current_connection = con_type; + +stm_ste_connection_error: return retval; } diff --git a/drivers/misc/stm.c b/drivers/misc/stm.c index a05b2d14573..53c47c1693a 100644 --- a/drivers/misc/stm.c +++ b/drivers/misc/stm.c @@ -73,6 +73,33 @@ static u64 stm_printk_buf[1024/sizeof(u64)]; static arch_spinlock_t stm_buf_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; +static char *mipi60 = "none"; +module_param(mipi60, charp, S_IRUGO); +MODULE_PARM_DESC(mipi60, "STM Trace to output on probe2 of mipi60 " + "('none' or 'ape' or 'modem')"); + +static char *mipi34 = "none"; +module_param(mipi34, charp, S_IRUGO); +MODULE_PARM_DESC(mipi34, "STM Trace to output on mipi34 " + "('none' or 'ape' or 'modem')"); + +static char *microsd = "none"; +module_param(microsd, charp, S_IRUGO); +MODULE_PARM_DESC(microsd, "STM Trace to output on SD card connector " + "('none' or 'ape' or 'modem')"); + +static unsigned int stm_ter; +module_param(stm_ter, uint, 0); +MODULE_PARM_DESC(stm_ter, "Value for STM_TER (trace control register). " + "Should be set by user as environment variable stm.stm_ter"); + +#define IS_APE_ON_MIPI34 (mipi34 && !strcmp(mipi34, "ape")) +#define IS_APE_ON_MIPI60 (mipi60 && !strcmp(mipi60, "ape")) +#define IS_APE_ON_MICROSD (microsd && !strcmp(microsd, "ape")) +#define IS_MODEM_ON_MICROSD (microsd && !strcmp(microsd, "modem")) + +static int stm_connection_set(void *data, u64 val); + int stm_alloc_channel(int offset) { int channel; @@ -251,6 +278,7 @@ EXPORT_SYMBOL(stm_trace_buffer_onchannel); static int stm_open(struct inode *inode, struct file *file) { struct channel_data *channel_data; + int retval = 0; channel_data = kzalloc(sizeof(struct channel_data), GFP_KERNEL); if (channel_data == NULL) @@ -260,7 +288,19 @@ static int stm_open(struct inode *inode, struct file *file) channel_data->numero = -1; /* Channel not yet allocated */ file->private_data = channel_data; - return 0; + /* + * Check if microsd is selected as trace interface + * and enable corresponding pins muxing. + */ + if (IS_MODEM_ON_MICROSD) + retval = stm_connection_set(NULL, STM_STE_MODEM_ON_MICROSD); + else if (IS_APE_ON_MICROSD) + retval = stm_connection_set(NULL, STM_STE_APE_ON_MICROSD); + + if (retval) + pr_alert("stm_open: failed to connect STM output\n"); + + return retval; } static int stm_release(struct inode *inode, struct file *file) @@ -338,6 +378,11 @@ static void stm_enable_src(unsigned int v) cr_val = readl(STM_CR); cr_val &= ~STM_CLOCK_MASK; writel(cr_val|(stm_clockdiv<stm_connection) { retval = stm.pdata->stm_connection(stm_connection); if (retval) { @@ -661,11 +713,13 @@ static int stm_connection_show(void *data, u64 *val) static int stm_connection_set(void *data, u64 val) { + int retval = 0; + if (stm.pdata->stm_connection) { stm_connection = val; - stm.pdata->stm_connection(val); + retval = stm.pdata->stm_connection(val); } - return 0; + return retval; } DEFINE_SIMPLE_ATTRIBUTE(stm_connection_fops, stm_connection_show, diff --git a/include/trace/stm.h b/include/trace/stm.h index 72e9136c25e..3cf11143c0e 100644 --- a/include/trace/stm.h +++ b/include/trace/stm.h @@ -64,7 +64,10 @@ enum stm_connection_type { STM_DEFAULT_CONNECTION = 1, STM_STE_MODEM_ON_MIPI34_NONE_ON_MIPI60 = 2, STM_STE_APE_ON_MIPI34_NONE_ON_MIPI60 = 3, - STM_STE_MODEM_ON_MIPI34_APE_ON_MIPI60 = 4 + STM_STE_MODEM_ON_MIPI34_APE_ON_MIPI60 = 4, + STM_STE_MODEM_ON_MICROSD = 5, + STM_STE_APE_ON_MICROSD = 6, + STM_STE_INVALID_CONNECTION = 0xff }; #ifdef __KERNEL__ -- cgit v1.2.3 From 045169df5cde22e97443190098394115b3c51385 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Thu, 12 Jan 2012 12:01:07 +0100 Subject: hwreg: ux500: Coding style fixes Fix the most obvious violations of the kernel coding style Signed-off-by: Jonas Aaberg --- arch/arm/mach-ux500/hwreg.c | 70 ++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 35 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/hwreg.c b/arch/arm/mach-ux500/hwreg.c index 1a47e60ed46..f35472e3ebf 100644 --- a/arch/arm/mach-ux500/hwreg.c +++ b/arch/arm/mach-ux500/hwreg.c @@ -1,4 +1,4 @@ -/* +%/* * Copyright (C) 2011 ST-Ericsson SA * * Author: Etienne CARRIERE for ST-Ericsson @@ -98,9 +98,8 @@ #include #include #include - -#include -#include +#include +#include #include @@ -138,9 +137,9 @@ struct hwreg_cfg { }; #define REG_FMT_DEC(c) ((c)->fmt & 0x1) /* bit 0: 0=hexa, 1=dec */ #define REG_FMT_HEX(c) (!REG_FMT_DEC(c)) /* bit 0: 0=hexa, 1=dec */ -#define REG_FMT_32B(c) (((c)->fmt & 0x6)==0x0) /* bit[2:1]=0 => 32b access */ -#define REG_FMT_16B(c) (((c)->fmt & 0x6)==0x2) /* bit[2:1]=1 => 16b access */ -#define REG_FMT_8B(c) (((c)->fmt & 0x6)==0x4) /* bit[2:1]=2 => 8b access */ +#define REG_FMT_32B(c) (((c)->fmt & 0x6) == 0x0) /* bit[2:1]=0 => 32b access */ +#define REG_FMT_16B(c) (((c)->fmt & 0x6) == 0x2) /* bit[2:1]=1 => 16b access */ +#define REG_FMT_8B(c) (((c)->fmt & 0x6) == 0x4) /* bit[2:1]=2 => 8b access */ static struct hwreg_cfg hwreg_cfg = { .addr = 0, /* default: invalid phys addr */ @@ -308,7 +307,7 @@ static ssize_t hwreg_address_write(struct file *file, if (err) return err; - if (hwreg_io_ptov(user_address)==NULL) + if (hwreg_io_ptov(user_address) == NULL) return -EADDRNOTAVAIL; debug_address = user_address; @@ -398,15 +397,15 @@ static const struct file_operations hwreg_map_fops = { static int hwreg_print(struct seq_file *s, void *d) { - struct hwreg_cfg *c = (struct hwreg_cfg*) s->private; + struct hwreg_cfg *c = (struct hwreg_cfg *) s->private; void *p; uint v; - if ((c==NULL) || ((p = hwreg_io_ptov(c->addr))==NULL)) + if ((c == NULL) || ((p = hwreg_io_ptov(c->addr)) == NULL)) return -EADDRNOTAVAIL; v = (uint) (REG_FMT_32B(c) ? readl(p) : REG_FMT_16B(c) ? readw(p) : readb(p)); - v = (c->shift>=0) ? v >> c->shift : v << (-c->shift); + v = (c->shift >= 0) ? v >> c->shift : v << (-c->shift); v = v & c->mask; if (REG_FMT_DEC(c)) @@ -434,16 +433,16 @@ static int hwreg_open(struct inode *inode, struct file *file) static int strval_len(char *b) { char *s = b; - if((*s=='0') && ((*(s+1)=='x') || (*(s+1)=='X'))) { + if ((*s == '0') && ((*(s+1) == 'x') || (*(s+1) == 'X'))) { s += 2; - for (; *s && (*s!=' ') && (*s!='\n'); s++) { + for (; *s && (*s != ' ') && (*s != '\n'); s++) { if (!isxdigit(*s)) return 0; } } else { - if (*s=='-') + if (*s == '-') s++; - for (; *s && (*s!=' ') && (*s!='\n'); s++) { + for (; *s && (*s != ' ') && (*s != '\n'); s++) { if (!isdigit(*s)) return 0; } @@ -457,7 +456,7 @@ static int strval_len(char *b) */ static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg) { - uint write, val=0, offset=0; + uint write, val = 0, offset = 0; struct hwreg_cfg loc = { .addr = 0, /* default: invalid phys addr */ .fmt = 0, /* default: 32bit access, hex output */ @@ -466,7 +465,7 @@ static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg) }; /* read or write ? */ - if(!strncmp(b, "read ", 5)) { + if (!strncmp(b, "read ", 5)) { write = 0; b += 5; } else if (!strncmp(b, "write ", 6)) { @@ -477,31 +476,31 @@ static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg) } /* OPTIONS -l|-w|-b -s -m -o */ - while((*b==' ') || (*b=='-')) { - if (*(b-1)!=' ') { + while ((*b == ' ') || (*b == '-')) { + if (*(b-1) != ' ') { b++; continue; } if ((!strncmp(b, "-d ", 3)) || (!strncmp(b, "-dec ", 5))) { - b += (*(b+2)==' ') ? 3 : 5; + b += (*(b+2) == ' ') ? 3 : 5; loc.fmt |= (1<<0); } else if ((!strncmp(b, "-h ", 3)) || (!strncmp(b, "-hex ", 5))) { - b += (*(b+2)==' ') ? 3 : 5; + b += (*(b+2) == ' ') ? 3 : 5; loc.fmt &= ~(1<<0); } else if ((!strncmp(b, "-m ", 3)) || (!strncmp(b, "-mask ", 6))) { - b += (*(b+2)==' ') ? 3 : 6; - if (strval_len(b)==0) + b += (*(b+2) == ' ') ? 3 : 6; + if (strval_len(b) == 0) return -EINVAL; loc.mask = simple_strtoul(b, &b, 0); - } else if ((!strncmp(b, "-s ", 3)) || (!strncmp(b,"-shift ", 7))) { - b += (*(b+2)==' ') ? 3 : 7; - if (strval_len(b)==0) + } else if ((!strncmp(b, "-s ", 3)) || (!strncmp(b, "-shift ", 7))) { + b += (*(b+2) == ' ') ? 3 : 7; + if (strval_len(b) == 0) return -EINVAL; loc.shift = simple_strtol(b, &b, 0); - } else if ((!strncmp(b, "-o ", 3)) || (!strncmp(b,"-offset ", 8))) { - b += (*(b+2)==' ') ? 3 : 8; - if (strval_len(b)==0) + } else if ((!strncmp(b, "-o ", 3)) || (!strncmp(b, "-offset ", 8))) { + b += (*(b+2) == ' ') ? 3 : 8; + if (strval_len(b) == 0) return -EINVAL; offset = simple_strtol(b, &b, 0); } else if (!strncmp(b, "-l ", 3)) { @@ -518,7 +517,7 @@ static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg) } } /* get arg ADDRESS */ - if (strval_len(b)==0) + if (strval_len(b) == 0) return -EINVAL; loc.addr = simple_strtoul(b, &b, 0); loc.addr += offset; @@ -526,8 +525,9 @@ static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg) return -EINVAL; if (write) { - while(*b==' ') b++; /* skip spaces up to arg VALUE */ - if (strval_len(b)==0) + while (*b == ' ') + b++; /* skip spaces up to arg VALUE */ + if (strval_len(b) == 0) return -EINVAL; val = simple_strtoul(b, &b, 0); } @@ -538,9 +538,9 @@ static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg) #ifdef DEBUG printk(KERN_INFO "HWREG request: %s %d-bit reg, %s, addr=0x%08X, " "mask=0x%X, shift=%d value=0x%X\n", - (write)?"write":"read", - REG_FMT_32B(cfg)?32:REG_FMT_16B(cfg)?16:8, - REG_FMT_DEC(cfg)?"decimal":"hexa", + (write) ? "write" : "read", + REG_FMT_32B(cfg) ? 32 : REG_FMT_16B(cfg) ? 16 : 8, + REG_FMT_DEC(cfg) ? "decimal" : "hexa", cfg->addr, cfg->mask, cfg->shift, val); #endif -- cgit v1.2.3 From 489a85202b27f8a2713b01733f6d17b2b4d283bb Mon Sep 17 00:00:00 2001 From: Michel JAOUEN Date: Thu, 12 Jan 2012 17:42:49 +0100 Subject: mach-ux500: hwreg adaptation for u9540 ST-Ericsson ID: 409625 ST-Ericsson FOSS-OUT ID: trivial ST-Ericsson Linux next: NA Depends-On: Iff4121811d2afbf581eec0905077c58bff96ce09 Change-Id: I121bd0f9732342ae5e6753e840473a618e1f3d9f Signed-off-by: Michel JAOUEN Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/45316 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Jonas ABERG --- arch/arm/mach-ux500/hwreg.c | 119 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 102 insertions(+), 17 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/hwreg.c b/arch/arm/mach-ux500/hwreg.c index f35472e3ebf..585f2a2b7be 100644 --- a/arch/arm/mach-ux500/hwreg.c +++ b/arch/arm/mach-ux500/hwreg.c @@ -1,4 +1,4 @@ -%/* +/* * Copyright (C) 2011 ST-Ericsson SA * * Author: Etienne CARRIERE for ST-Ericsson @@ -156,10 +156,12 @@ struct hwreg_io_range { u8 *addr; }; +static struct hwreg_io_range *hwreg_io_current_map; + /* * HWREG guts: mapping table */ -static struct hwreg_io_range hwreg_io_map[] = { +static struct hwreg_io_range hwreg_u8500_io_map[] = { /* Periph1 Peripherals */ {.base = U8500_PER1_BASE, .size = 0x10000}, /* Periph2 Peripherals */ @@ -237,17 +239,89 @@ static struct hwreg_io_range hwreg_io_map[] = { }; +static struct hwreg_io_range hwreg_u9540_io_map[] = { + /* Periph1 Peripherals */ + {.base = U8500_PER1_BASE, .size = 0x10000}, + /* Periph2 Peripherals */ + {.base = U8500_PER2_BASE, .size = 0x10000}, + /* Periph3 Peripherals */ + {.base = U8500_PER3_BASE, .size = 0x10000}, + /* Periph4 Peripherals */ + {.base = U8500_PER4_BASE, .size = 0x70000}, + /* Periph5 Periphals */ + {.base = U8500_PER5_BASE, .size = 0x20000}, + /* Periph6 Peripherals */ + {.base = U8500_PER6_BASE, .size = 0x10000}, + /* + * Snoop Control Unit, A9 Private interrupt IF, + * A9 private peripherals, Level-2 Cache Configuration registers, + * and some reserved area + */ + {.base = U8500_SCU_BASE, .size = 0x4000}, + + /* DISPLAY Ctrl. configuration registers */ + {.base = U8500_MCDE_BASE, .size = SZ_4K}, + + /* DSI1 link registers */ + {.base = U8500_DSI_LINK1_BASE, .size = SZ_4K}, + + /* DSI2 link registers */ + {.base = U8500_DSI_LINK2_BASE, .size = SZ_4K}, + + /* DSI3 link registers */ + {.base = U8500_DSI_LINK3_BASE, .size = SZ_4K}, + + /* DMA Ctrl. configuration registers (base address changed in V1) */ + {.base = U8500_DMA_BASE, .size = SZ_4K}, + + /* 0xB7A00000 -> 0xB7E04000: Modem I2C */ + {.base = U8500_MODEM_I2C, .size = 0x404000}, + + /* 0xA0390000 -> 0xA039FFFF: SBAG configuration registers */ + {.base = U8500_SBAG_BASE, .size = SZ_4K}, + + /* 0xA0300000 -> 0xA031FFFF: SGA configuration registers */ + {.base = U8500_SGA_BASE, .size = 0x10000}, + + /* 0xA0200000 -> 0xA02FFFFF: Smart Imaging Acc. Data Memory space (SIA) + */ + {.base = U8500_SIA_BASE, .size = 0x60000}, + + /* 0xA0100000 -> 0xA01FFFFF: Smart Video Acc. Data Memory space (SVA) */ + {.base = U8500_SVA_BASE, .size = 0x60000}, + + /* 0x81000000 -> 0x8103FFFF: Main ICN Crossbar configuration registers + */ + {.base = U8500_ICN_BASE, .size = 0x2000}, + + /* 0x80140000 -> 0x8014FFFF: HSEM (Semaphores) configuration */ + {.base = U8500_HSEM_BASE, .size = SZ_4K}, + + /* 0x80130000 -> 0x8013FFFF: B2R2 configuration registers */ + {.base = U8500_B2R2_BASE, .size = SZ_4K}, + + /* 0x80100000 -> 0x8010FFFF: STM */ + {.base = U8500_STM_BASE, .size = 0x10000}, + + /* High part of embedded boot ROM */ + {.base = U9540_ASIC_ID_BASE, .size = SZ_4K}, + + {.base = 0, .size = 0, }, + +}; + static void hwreg_io_init(void) { int i; - for (i = 0; hwreg_io_map[i].base; ++i) { - hwreg_io_map[i].addr = ioremap(hwreg_io_map[i].base, - hwreg_io_map[i].size); - if (!hwreg_io_map[i].addr) + for (i = 0; hwreg_io_current_map[i].base; ++i) { + hwreg_io_current_map[i].addr = + ioremap(hwreg_io_current_map[i].base, + hwreg_io_current_map[i].size); + if (!hwreg_io_current_map[i].addr) printk(KERN_WARNING "%s: ioremap for %d (%08x) failed\n", - __func__, i, hwreg_io_map[i].base); + __func__, i, hwreg_io_current_map[i].base); } } @@ -255,19 +329,19 @@ static void hwreg_io_exit(void) { int i; - for (i = 0; hwreg_io_map[i].base; ++i) - if (hwreg_io_map[i].addr) - iounmap(hwreg_io_map[i].addr); + for (i = 0; hwreg_io_current_map[i].base; ++i) + if (hwreg_io_current_map[i].addr) + iounmap(hwreg_io_current_map[i].addr); } static void *hwreg_io_ptov(u32 phys) { int i; - for (i = 0; hwreg_io_map[i].base; ++i) { - u32 base = hwreg_io_map[i].base; - u32 size = hwreg_io_map[i].size; - u8 *addr = hwreg_io_map[i].addr; + for (i = 0; hwreg_io_current_map[i].base; ++i) { + u32 base = hwreg_io_current_map[i].base; + u32 size = hwreg_io_current_map[i].size; + u8 *addr = hwreg_io_current_map[i].addr; if (phys < base || phys >= base + size) continue; @@ -369,10 +443,12 @@ static const struct file_operations hwreg_value_fops = { static int hwreg_map_print(struct seq_file *s, void *p) { int err, i; - for (i = 0; hwreg_io_map[i].base; ++i) { + + for (i = 0; hwreg_io_current_map[i].base; ++i) { err = seq_printf(s, "%d: 0x%08X => 0x%08X\n", - i, hwreg_io_map[i].base, - hwreg_io_map[i].base+hwreg_io_map[i].size); + i, hwreg_io_current_map[i].base, + hwreg_io_current_map[i].base + + hwreg_io_current_map[i].size); if (err < 0) return -ENOMEM; } @@ -602,6 +678,15 @@ static const struct file_operations hwreg_fops = { static int __init hwreg_initialize(void) { static struct dentry *file; + + if (cpu_is_u9540()) { + printk(KERN_INFO "hwreg: cpu is U9540\n"); + hwreg_io_current_map = hwreg_u9540_io_map; + } else { + printk(KERN_INFO "hwreg: cpu is U8500\n"); + hwreg_io_current_map = hwreg_u8500_io_map; + } + hwreg_io_init(); hwreg_debugfs_dir = debugfs_create_dir("mem", NULL); -- cgit v1.2.3 From 0e76cb07853419546152e353b79b24807c6d5663 Mon Sep 17 00:00:00 2001 From: Yann Gautier Date: Tue, 10 Jan 2012 09:36:14 +0100 Subject: stm: mach-ux500: Add support for 9540 ST-Ericsson ID: 398896 Signed-off-by: Yann Gautier --- arch/arm/mach-ux500/board-mop500-stm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/board-mop500-stm.c b/arch/arm/mach-ux500/board-mop500-stm.c index d38595b11b2..5a634745bad 100644 --- a/arch/arm/mach-ux500/board-mop500-stm.c +++ b/arch/arm/mach-ux500/board-mop500-stm.c @@ -203,7 +203,7 @@ static void control_level_shifter_for_microsd(int gpio_dir) { int gpio[2]; - if (machine_is_hrefv60()) { + if (machine_is_hrefv60() || machine_is_u9540()) { gpio[0] = HREFV60_SDMMC_EN_GPIO; gpio[1] = HREFV60_SDMMC_1V8_3V_GPIO; } else { -- cgit v1.2.3 From eacc602b9c20b99406705804c4e216f18403f7d7 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Thu, 2 Feb 2012 11:36:49 +0100 Subject: stm: ux500: Add U8520 machine ST-Ericsson ID: 371953 Signed-off-by: Bengt Jonsson --- arch/arm/mach-ux500/board-mop500-stm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/board-mop500-stm.c b/arch/arm/mach-ux500/board-mop500-stm.c index 5a634745bad..34e5892d18b 100644 --- a/arch/arm/mach-ux500/board-mop500-stm.c +++ b/arch/arm/mach-ux500/board-mop500-stm.c @@ -203,7 +203,7 @@ static void control_level_shifter_for_microsd(int gpio_dir) { int gpio[2]; - if (machine_is_hrefv60() || machine_is_u9540()) { + if (machine_is_hrefv60() || machine_is_u8520() || machine_is_u9540()) { gpio[0] = HREFV60_SDMMC_EN_GPIO; gpio[1] = HREFV60_SDMMC_1V8_3V_GPIO; } else { -- cgit v1.2.3 From 647bf84aaa59424e0b3ca9b8c181c7daed11bf2c Mon Sep 17 00:00:00 2001 From: Johan Rudholm Date: Thu, 2 Feb 2012 14:54:37 +0100 Subject: stm: mach-ux500: Update U8520 SD-card GPIO pins ST-Ericsson ID: 371953 Signed-off-by: Bengt Jonsson --- arch/arm/mach-ux500/board-mop500-stm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-ux500/board-mop500-stm.c b/arch/arm/mach-ux500/board-mop500-stm.c index 34e5892d18b..1bef2a01873 100644 --- a/arch/arm/mach-ux500/board-mop500-stm.c +++ b/arch/arm/mach-ux500/board-mop500-stm.c @@ -26,6 +26,9 @@ #define HREFV60_SDMMC_EN_GPIO 169 #define HREFV60_SDMMC_1V8_3V_GPIO 5 +#define U8520_SDMMC_EN_GPIO 78 +#define U8520_SDMMC_1V8_3V_GPIO 5 + #define STM_DEVICE (&u8500_stm_device.dev) #define STM_ERR(msg) dev_err(STM_DEVICE, msg) #define STM_WARN(msg) dev_warn(STM_DEVICE, msg) @@ -203,9 +206,12 @@ static void control_level_shifter_for_microsd(int gpio_dir) { int gpio[2]; - if (machine_is_hrefv60() || machine_is_u8520() || machine_is_u9540()) { + if (machine_is_hrefv60() || machine_is_u9540()) { gpio[0] = HREFV60_SDMMC_EN_GPIO; gpio[1] = HREFV60_SDMMC_1V8_3V_GPIO; + } else if (machine_is_u8520()) { + gpio[0] = U8520_SDMMC_EN_GPIO; + gpio[1] = U8520_SDMMC_1V8_3V_GPIO; } else { gpio[0] = MOP500_EGPIO(17); gpio[1] = MOP500_EGPIO(18); -- cgit v1.2.3