lkml.org 
[lkml]   [2011]   [Aug]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 20/24] C6X: general SoC support
    Date
    This patch provides a soc_ops struct which provides hooks for SoC functionality
    which doesn't fit well into other places. For instance, all SoCs have a silicon
    revision but each requires different ways to get at that revision.

    Signed-off-by: Mark Salter <msalter@redhat.com>
    ---
    arch/c6x/include/asm/soc.h | 126 +++++++++++++++++++++++++++++++++
    arch/c6x/kernel/soc.c | 168 ++++++++++++++++++++++++++++++++++++++++++++
    2 files changed, 294 insertions(+), 0 deletions(-)
    create mode 100644 arch/c6x/include/asm/soc.h
    create mode 100644 arch/c6x/kernel/soc.c

    diff --git a/arch/c6x/include/asm/soc.h b/arch/c6x/include/asm/soc.h
    new file mode 100644
    index 0000000..72719aa
    --- /dev/null
    +++ b/arch/c6x/include/asm/soc.h
    @@ -0,0 +1,126 @@
    +/*
    + * Miscellaneous SoC-specific hooks.
    + *
    + * Copyright (C) 2011 Texas Instruments Incorporated
    + *
    + * Author: Mark Salter <msalter@redhat.com>
    + *
    + * This file is licensed under the terms of the GNU General Public License
    + * version 2. This program is licensed "as is" without any warranty of any
    + * kind, whether express or implied.
    + */
    +#ifndef _ASM_C6X_SOC_H
    +#define _ASM_C6X_SOC_H
    +
    +/*
    + * IDs of devices that may be enabled/disabled through SoC-specific registers.
    + * Any given SoC will only support a subset of these.
    + */
    +enum soc_device_id {
    + SOC_DEV_TCP = 0,
    + SOC_DEV_VCP,
    + SOC_DEV_EMAC,
    + SOC_DEV_TIMER,
    + SOC_DEV_GPIO,
    + SOC_DEV_I2C,
    + SOC_DEV_MCBSP,
    + SOC_DEV_HPI,
    + SOC_DEV_PCI,
    + SOC_DEV_UTOPIA,
    + SOC_DEV_SRIO,
    + SOC_DEV_EMIF,
    + SOC_DEV_DDR2,
    + SOC_DEV_TSIP,
    +
    + SOC_DEV_MAX
    +};
    +
    +/* MACSEL values */
    +#define MACSEL_UNKNOWN 0
    +#define MACSEL_DISABLED 1 /* SoCs may have EMAC disabled with input pin */
    +#define MACSEL_MII 2
    +#define MACSEL_RMII 3
    +#define MACSEL_GMII 4
    +#define MACSEL_RGMII 5
    +#define MACSEL_S3MII 6
    +#define MACSEL_SGMII 7
    +
    +struct soc_ops {
    + const char *compat;
    + const char *name;
    +
    + /* Setup function called by setup_arch() */
    + void (*setup_arch)(void);
    +
    + /* Return silicon rev and optionally, a string representation */
    + unsigned int (*silicon_rev)(char **rev_str);
    +
    + /* IRQ initialization */
    + void (*init_IRQ)(void);
    +
    + /* timer initialization */
    + void (*time_init)(void);
    +
    + /* Return active exception event or -1 if none */
    + int (*get_exception)(void);
    +
    + /* Assert an event */
    + void (*assert_event)(unsigned int evt);
    +
    + /* Get MAC config for given EMAC */
    + int (*macsel)(unsigned int mac_index);
    +
    + /* Get MAC address for given EMAC */
    + int (*mac_addr)(unsigned int mac_index, u8 *addr);
    +
    + /* Boot/reset cores */
    + void (*boot_core)(int corenum);
    + void (*reset_core)(int corenum);
    +
    + /* Enable/disable power/clocks/buffers for SoC devices */
    + void (*dev_enable)(enum soc_device_id id, int index);
    + void (*dev_disable)(enum soc_device_id id, int index);
    +
    + /* Chip-level RMII reset for EMAC modules */
    + void (*rmii_reset_ctl)(int index, int assert);
    +};
    +
    +extern struct soc_ops soc_ops;
    +
    +#define __soc_ops __attribute__((__section__(".soc.ops")))
    +
    +#define define_soc(name) \
    + extern struct soc_ops soc_ops_##name; \
    + struct soc_ops soc_ops_##name __soc_ops =
    +
    +extern struct soc_ops __soc_ops_start;
    +extern struct soc_ops __soc_ops_end;
    +
    +/*
    + * This is used to translate soc_devive_ id into SoC-specific id.
    + */
    +extern int soc_dev_table[SOC_DEV_MAX];
    +#define SOC_DEVCONFIG_SUPPORT(a, b) soc_dev_table[SOC_DEV_##a] = (b)
    +
    +
    +extern unsigned int soc_silicon_rev(char **rev_str);
    +extern void soc_init_IRQ(void);
    +extern void soc_time_init(void);
    +extern int soc_get_exception(void);
    +extern void soc_assert_event(unsigned int event);
    +extern int soc_macsel(unsigned int index);
    +extern int soc_mac_addr(unsigned int index, u8 *addr);
    +extern void soc_boot_core(int corenum);
    +extern void soc_reset_core(int corenum);
    +extern void soc_dev_enable(enum soc_device_id id, unsigned int index);
    +extern void soc_dev_disable(enum soc_device_id id, unsigned int index);
    +extern void soc_rmii_reset_ctl(int index, int assert);
    +extern void soc_arch_init(void);
    +
    +/*
    + * for mmio on SoC devices. regs are always same byte order as cpu.
    + */
    +#define soc_readl(addr) __raw_readl(addr)
    +#define soc_writel(b, addr) __raw_writel((b), (addr))
    +
    +#endif /* _ASM_C6X_SOC_H */
    diff --git a/arch/c6x/kernel/soc.c b/arch/c6x/kernel/soc.c
    new file mode 100644
    index 0000000..6effec1
    --- /dev/null
    +++ b/arch/c6x/kernel/soc.c
    @@ -0,0 +1,168 @@
    +/*
    + * Miscellaneous SoC-specific hooks.
    + *
    + * Copyright (C) 2011 Texas Instruments Incorporated
    + * Author: Mark Salter <msalter@redhat.com>
    + *
    + * 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 <linux/module.h>
    +#include <linux/ctype.h>
    +#include <asm/system.h>
    +#include <asm/setup.h>
    +#include <asm/soc.h>
    +
    +struct soc_ops soc_ops;
    +
    +unsigned int soc_silicon_rev(char **rev_str)
    +{
    + if (!soc_ops.silicon_rev) {
    + if (rev_str)
    + *rev_str = "unknown";
    + return 0;
    + }
    + return soc_ops.silicon_rev(rev_str);
    +}
    +EXPORT_SYMBOL(soc_silicon_rev);
    +
    +void soc_init_IRQ(void)
    +{
    + if (soc_ops.init_IRQ)
    + soc_ops.init_IRQ();
    +}
    +
    +void soc_time_init(void)
    +{
    + if (soc_ops.time_init)
    + soc_ops.time_init();
    +}
    +
    +int soc_get_exception(void)
    +{
    + if (!soc_ops.get_exception)
    + return -1;
    + return soc_ops.get_exception();
    +}
    +
    +void soc_assert_event(unsigned int evt)
    +{
    + if (soc_ops.assert_event)
    + soc_ops.assert_event(evt);
    +}
    +
    +int soc_macsel(unsigned int index)
    +{
    + if (!soc_ops.macsel)
    + return MACSEL_MII;
    +
    + return soc_ops.macsel(index);
    +}
    +EXPORT_SYMBOL(soc_macsel);
    +
    +static u8 cmdline_mac[6];
    +
    +static int __init get_mac_addr_from_cmdline(char *str)
    +{
    + int count, i, val;
    +
    + for (count = 0; count < 6 && *str; count++, str += 3) {
    + if (!isxdigit(str[0]) || !isxdigit(str[1]))
    + return 0;
    + if (str[2] != ((count < 5) ? ':' : '\0'))
    + return 0;
    +
    + for (i = 0, val = 0; i < 2; i++) {
    + val = val << 4;
    + val |= isdigit(str[i]) ?
    + str[i] - '0' : toupper(str[i]) - 'A' + 10;
    + }
    + cmdline_mac[count] = val;
    + }
    + return 1;
    +}
    +__setup("emac_addr=", get_mac_addr_from_cmdline);
    +
    +int soc_mac_addr(unsigned int index, u8 *addr)
    +{
    + int i, found = 0;
    +
    + for (i = 0; i < 6; i++) {
    + if (cmdline_mac[i]) {
    + found = 1;
    + break;
    + }
    + }
    +
    + if (found) {
    + /* cmdline overrides hardware MAC */
    + memcpy(addr, cmdline_mac, 6);
    +
    + /* adjust for specific EMAC device */
    + addr[5] += index * c6x_num_cores;
    + return 1;
    + }
    +
    + if (!soc_ops.mac_addr)
    + return 0;
    +
    + found = soc_ops.mac_addr(index, addr);
    + if (!found && index) {
    + /* try basing address off index 0 address */
    + found = soc_ops.mac_addr(0, addr);
    + if (!found)
    + return 0;
    + addr[5] += index * c6x_num_cores;
    + }
    +
    + return found;
    +}
    +EXPORT_SYMBOL(soc_mac_addr);
    +
    +void soc_boot_core(int corenum)
    +{
    + if (!soc_ops.boot_core ||
    + corenum < 0 || corenum >= c6x_num_cores ||
    + corenum == get_coreid())
    + return;
    +
    + printk(KERN_INFO "Booting core %d\n", corenum);
    + soc_ops.boot_core(corenum);
    +}
    +
    +void soc_reset_core(int corenum)
    +{
    + if (!soc_ops.reset_core ||
    + corenum < 0 || corenum >= c6x_num_cores ||
    + corenum == get_coreid())
    + return;
    +
    + printk(KERN_INFO "Resetting core %d\n", corenum);
    + soc_ops.reset_core(corenum);
    +}
    +
    +int soc_dev_table[SOC_DEV_MAX];
    +
    +void soc_dev_enable(enum soc_device_id id, unsigned int index)
    +{
    + if (!soc_ops.dev_enable)
    + return;
    +
    + soc_ops.dev_enable(soc_dev_table[id], index);
    +}
    +
    +void soc_dev_disable(enum soc_device_id id, unsigned int index)
    +{
    + if (!soc_ops.dev_disable)
    + return;
    +
    + soc_ops.dev_disable(soc_dev_table[id], index);
    +}
    +
    +void soc_rmii_reset_ctl(int index, int assert)
    +{
    + if (!soc_ops.rmii_reset_ctl)
    + return;
    + soc_ops.rmii_reset_ctl(index, assert);
    +}
    --
    1.7.6


    \
     
     \ /
      Last update: 2011-08-31 23:31    [W:0.041 / U:32.064 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site