Skip to content

Commit

Permalink
[ARM] pxa: make MFP configuration processor independent
Browse files Browse the repository at this point in the history
There are two reasons for making the MFP configuration to be processor
independent, i.e. removing the relationship of configuration bits with
actual MFPR register settings:

   1. power management sometimes requires the MFP to be configured
      differently when in run mode or in low power mode

   2. for future integration of pxa{25x,27x} GPIO configurations

The modifications include:

1. introducing of processor independent MFP configuration bits, as
   defined in [include/asm-arm/arch-pxa/mfp.h]:

	bit  0.. 9 - MFP Pin Number (1024 Pins Maximum)
	bit 10..12 - Alternate Function Selection
	bit 13..15 - Drive Strength
	bit 16..18 - Low Power Mode State
	bit 19..20 - Low Power Mode Edge Detection
	bit 21..22 - Run Mode Pull State
	and so on,

2. moving the processor dependent code from mfp.h into mfp-pxa3xx.h

3. cleaning up of the MFPR bit definitions

4. mapping of processor independent MFP configuration into processor
   specific MFPR register settings is now totally encapsulated within
   pxa3xx_mfp_config()

5. using of "unsigned long" instead of invented type of "mfp_cfg_t"
   according to Documentation/CodingStyle Chapter 5, usage of this
   in platform code will be slowly removed in later patches

Signed-off-by: eric miao <eric.miao@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
eric miao authored and Russell King committed Jan 26, 2008
1 parent 0ad1fbc commit 7f7c8a6
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 209 deletions.
97 changes: 82 additions & 15 deletions arch/arm/mach-pxa/mfp.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <asm/hardware.h>
#include <asm/arch/mfp.h>
#include <asm/arch/mfp-pxa3xx.h>

/* mfp_spin_lock is used to ensure that MFP register configuration
* (most likely a read-modify-write operation) is atomic, and that
Expand All @@ -28,43 +29,105 @@
static DEFINE_SPINLOCK(mfp_spin_lock);

static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);

struct pxa3xx_mfp_pin {
unsigned long config; /* -1 for not configured */
unsigned long mfpr_off; /* MFPRxx Register offset */
unsigned long mfpr_run; /* Run-Mode Register Value */
unsigned long mfpr_lpm; /* Low Power Mode Register Value */
};

static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];

/* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */
const static unsigned long mfpr_lpm[] = {
MFPR_LPM_INPUT,
MFPR_LPM_DRIVE_LOW,
MFPR_LPM_DRIVE_HIGH,
MFPR_LPM_PULL_LOW,
MFPR_LPM_PULL_HIGH,
MFPR_LPM_FLOAT,
};

/* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */
const static unsigned long mfpr_pull[] = {
MFPR_PULL_NONE,
MFPR_PULL_LOW,
MFPR_PULL_HIGH,
MFPR_PULL_BOTH,
};

/* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */
const static unsigned long mfpr_edge[] = {
MFPR_EDGE_NONE,
MFPR_EDGE_RISE,
MFPR_EDGE_FALL,
MFPR_EDGE_BOTH,
};

#define mfpr_readl(off) \
__raw_readl(mfpr_mmio_base + (off))

#define mfpr_writel(off, val) \
__raw_writel(val, mfpr_mmio_base + (off))

#define mfp_configured(p) ((p)->config != -1)

/*
* perform a read-back of any MFPR register to make sure the
* previous writings are finished
*/
#define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0)

static inline void __mfp_config(int pin, unsigned long val)
static inline void __mfp_config_run(struct pxa3xx_mfp_pin *p)
{
unsigned long off = mfp_table[pin].mfpr_off;
if (mfp_configured(p))
mfpr_writel(p->mfpr_off, p->mfpr_run);
}

mfp_table[pin].mfpr_val = val;
mfpr_writel(off, val);
static inline void __mfp_config_lpm(struct pxa3xx_mfp_pin *p)
{
if (mfp_configured(p) && p->mfpr_lpm != p->mfpr_run)
mfpr_writel(p->mfpr_off, p->mfpr_lpm);
}

void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num)
void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num)
{
int i, pin;
unsigned long val, flags;
mfp_cfg_t *mfp_cfg = mfp_cfgs;
unsigned long flags;
int i;

spin_lock_irqsave(&mfp_spin_lock, flags);

for (i = 0; i < num; i++, mfp_cfg++) {
pin = MFP_CFG_PIN(*mfp_cfg);
val = MFP_CFG_VAL(*mfp_cfg);
for (i = 0; i < num; i++, mfp_cfgs++) {
unsigned long tmp, c = *mfp_cfgs;
struct pxa3xx_mfp_pin *p;
int pin, af, drv, lpm, edge, pull;

pin = MFP_PIN(c);
BUG_ON(pin >= MFP_PIN_MAX);

__mfp_config(pin, val);
p = &mfp_table[pin];

af = MFP_AF(c);
drv = MFP_DS(c);
lpm = MFP_LPM_STATE(c);
edge = MFP_LPM_EDGE(c);
pull = MFP_PULL(c);

/* run-mode pull settings will conflict with MFPR bits of
* low power mode state, calculate mfpr_run and mfpr_lpm
* individually if pull != MFP_PULL_NONE
*/
tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv);

if (likely(pull == MFP_PULL_NONE)) {
p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
p->mfpr_lpm = p->mfpr_run;
} else {
p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
p->mfpr_run = tmp | mfpr_pull[pull];
}

p->config = c; __mfp_config_run(p);
}

mfpr_sync();
Expand Down Expand Up @@ -110,7 +173,8 @@ void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)

do {
mfp_table[i].mfpr_off = offset;
mfp_table[i].mfpr_val = 0;
mfp_table[i].mfpr_run = 0;
mfp_table[i].mfpr_lpm = 0;
offset += 4; i++;
} while ((i <= p->end) && (p->end != -1));
}
Expand All @@ -120,5 +184,8 @@ void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)

void __init pxa3xx_init_mfp(void)
{
memset(mfp_table, 0, sizeof(mfp_table));
int i;

for (i = 0; i < ARRAY_SIZE(mfp_table); i++)
mfp_table[i].config = -1;
}
115 changes: 115 additions & 0 deletions include/asm-arm/arch-pxa/mfp-pxa3xx.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,69 @@
#ifndef __ASM_ARCH_MFP_PXA3XX_H
#define __ASM_ARCH_MFP_PXA3XX_H

#define MFPR_BASE (0x40e10000)
#define MFPR_SIZE (PAGE_SIZE)

/* MFPR register bit definitions */
#define MFPR_PULL_SEL (0x1 << 15)
#define MFPR_PULLUP_EN (0x1 << 14)
#define MFPR_PULLDOWN_EN (0x1 << 13)
#define MFPR_SLEEP_SEL (0x1 << 9)
#define MFPR_SLEEP_OE_N (0x1 << 7)
#define MFPR_EDGE_CLEAR (0x1 << 6)
#define MFPR_EDGE_FALL_EN (0x1 << 5)
#define MFPR_EDGE_RISE_EN (0x1 << 4)

#define MFPR_SLEEP_DATA(x) ((x) << 8)
#define MFPR_DRIVE(x) (((x) & 0x7) << 10)
#define MFPR_AF_SEL(x) (((x) & 0x7) << 0)

#define MFPR_EDGE_NONE (0)
#define MFPR_EDGE_RISE (MFPR_EDGE_RISE_EN)
#define MFPR_EDGE_FALL (MFPR_EDGE_FALL_EN)
#define MFPR_EDGE_BOTH (MFPR_EDGE_RISE | MFPR_EDGE_FALL)

/*
* Table that determines the low power modes outputs, with actual settings
* used in parentheses for don't-care values. Except for the float output,
* the configured driven and pulled levels match, so if there is a need for
* non-LPM pulled output, the same configuration could probably be used.
*
* Output value sleep_oe_n sleep_data pullup_en pulldown_en pull_sel
* (bit 7) (bit 8) (bit 14) (bit 13) (bit 15)
*
* Input 0 X(0) X(0) X(0) 0
* Drive 0 0 0 0 X(1) 0
* Drive 1 0 1 X(1) 0 0
* Pull hi (1) 1 X(1) 1 0 0
* Pull lo (0) 1 X(0) 0 1 0
* Z (float) 1 X(0) 0 0 0
*/
#define MFPR_LPM_INPUT (0)
#define MFPR_LPM_DRIVE_LOW (MFPR_SLEEP_DATA(0) | MFPR_PULLDOWN_EN)
#define MFPR_LPM_DRIVE_HIGH (MFPR_SLEEP_DATA(1) | MFPR_PULLUP_EN)
#define MFPR_LPM_PULL_LOW (MFPR_LPM_DRIVE_LOW | MFPR_SLEEP_OE_N)
#define MFPR_LPM_PULL_HIGH (MFPR_LPM_DRIVE_HIGH | MFPR_SLEEP_OE_N)
#define MFPR_LPM_FLOAT (MFPR_SLEEP_OE_N)
#define MFPR_LPM_MASK (0xe080)

/*
* The pullup and pulldown state of the MFP pin at run mode is by default
* determined by the selected alternate function. In case that some buggy
* devices need to override this default behavior, the definitions below
* indicates the setting of corresponding MFPR bits
*
* Definition pull_sel pullup_en pulldown_en
* MFPR_PULL_NONE 0 0 0
* MFPR_PULL_LOW 1 0 1
* MFPR_PULL_HIGH 1 1 0
* MFPR_PULL_BOTH 1 1 1
*/
#define MFPR_PULL_NONE (0)
#define MFPR_PULL_LOW (MFPR_PULL_SEL | MFPR_PULLDOWN_EN)
#define MFPR_PULL_BOTH (MFPR_PULL_LOW | MFPR_PULLUP_EN)
#define MFPR_PULL_HIGH (MFPR_PULL_SEL | MFPR_PULLUP_EN)

/* PXA3xx common MFP configurations - processor specific ones defined
* in mfp-pxa300.h and mfp-pxa320.h
*/
Expand Down Expand Up @@ -134,4 +197,56 @@
#define GPIO5_2_GPIO MFP_CFG(GPIO5_2, AF0)
#define GPIO6_2_GPIO MFP_CFG(GPIO6_2, AF0)

/*
* each MFP pin will have a MFPR register, since the offset of the
* register varies between processors, the processor specific code
* should initialize the pin offsets by pxa3xx_mfp_init_addr()
*
* pxa3xx_mfp_init_addr - accepts a table of "pxa3xx_mfp_addr_map"
* structure, which represents a range of MFP pins from "start" to
* "end", with the offset begining at "offset", to define a single
* pin, let "end" = -1
*
* use
*
* MFP_ADDR_X() to define a range of pins
* MFP_ADDR() to define a single pin
* MFP_ADDR_END to signal the end of pin offset definitions
*/
struct pxa3xx_mfp_addr_map {
unsigned int start;
unsigned int end;
unsigned long offset;
};

#define MFP_ADDR_X(start, end, offset) \
{ MFP_PIN_##start, MFP_PIN_##end, offset }

#define MFP_ADDR(pin, offset) \
{ MFP_PIN_##pin, -1, offset }

#define MFP_ADDR_END { MFP_PIN_INVALID, 0 }

/*
* pxa3xx_mfp_read()/pxa3xx_mfp_write() - for direct read/write access
* to the MFPR register
*/
unsigned long pxa3xx_mfp_read(int mfp);
void pxa3xx_mfp_write(int mfp, unsigned long mfpr_val);

/*
* pxa3xx_mfp_config - configure the MFPR registers
*
* used by board specific initialization code
*/
void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num);

/*
* pxa3xx_mfp_init_addr() - initialize the mapping between mfp pin
* index and MFPR register offset
*
* used by processor specific code
*/
void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *);
void __init pxa3xx_init_mfp(void);
#endif /* __ASM_ARCH_MFP_PXA3XX_H */
Loading

0 comments on commit 7f7c8a6

Please sign in to comment.