^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/arch/arm/plat-pxa/mfp.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Multi-Function Pin Support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2007 Marvell Internation Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * 2007-08-21: eric miao <eric.miao@marvell.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * initial version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <plat/mfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define MFPR_SIZE (PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* MFPR register bit definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define MFPR_PULL_SEL (0x1 << 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define MFPR_PULLUP_EN (0x1 << 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define MFPR_PULLDOWN_EN (0x1 << 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define MFPR_SLEEP_SEL (0x1 << 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define MFPR_SLEEP_OE_N (0x1 << 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define MFPR_EDGE_CLEAR (0x1 << 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define MFPR_EDGE_FALL_EN (0x1 << 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define MFPR_EDGE_RISE_EN (0x1 << 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define MFPR_SLEEP_DATA(x) ((x) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define MFPR_DRIVE(x) (((x) & 0x7) << 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define MFPR_AF_SEL(x) (((x) & 0x7) << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define MFPR_EDGE_NONE (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define MFPR_EDGE_RISE (MFPR_EDGE_RISE_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define MFPR_EDGE_FALL (MFPR_EDGE_FALL_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define MFPR_EDGE_BOTH (MFPR_EDGE_RISE | MFPR_EDGE_FALL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * Table that determines the low power modes outputs, with actual settings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * used in parentheses for don't-care values. Except for the float output,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * the configured driven and pulled levels match, so if there is a need for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * non-LPM pulled output, the same configuration could probably be used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * Output value sleep_oe_n sleep_data pullup_en pulldown_en pull_sel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * (bit 7) (bit 8) (bit 14) (bit 13) (bit 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * Input 0 X(0) X(0) X(0) 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * Drive 0 0 0 0 X(1) 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * Drive 1 0 1 X(1) 0 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * Pull hi (1) 1 X(1) 1 0 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * Pull lo (0) 1 X(0) 0 1 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * Z (float) 1 X(0) 0 0 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define MFPR_LPM_INPUT (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define MFPR_LPM_DRIVE_LOW (MFPR_SLEEP_DATA(0) | MFPR_PULLDOWN_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define MFPR_LPM_DRIVE_HIGH (MFPR_SLEEP_DATA(1) | MFPR_PULLUP_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define MFPR_LPM_PULL_LOW (MFPR_LPM_DRIVE_LOW | MFPR_SLEEP_OE_N)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define MFPR_LPM_PULL_HIGH (MFPR_LPM_DRIVE_HIGH | MFPR_SLEEP_OE_N)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define MFPR_LPM_FLOAT (MFPR_SLEEP_OE_N)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define MFPR_LPM_MASK (0xe080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * The pullup and pulldown state of the MFP pin at run mode is by default
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * determined by the selected alternate function. In case that some buggy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * devices need to override this default behavior, the definitions below
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * indicates the setting of corresponding MFPR bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * Definition pull_sel pullup_en pulldown_en
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * MFPR_PULL_NONE 0 0 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * MFPR_PULL_LOW 1 0 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * MFPR_PULL_HIGH 1 1 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * MFPR_PULL_BOTH 1 1 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * MFPR_PULL_FLOAT 1 0 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define MFPR_PULL_NONE (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define MFPR_PULL_LOW (MFPR_PULL_SEL | MFPR_PULLDOWN_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define MFPR_PULL_BOTH (MFPR_PULL_LOW | MFPR_PULLUP_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define MFPR_PULL_HIGH (MFPR_PULL_SEL | MFPR_PULLUP_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define MFPR_PULL_FLOAT (MFPR_PULL_SEL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* mfp_spin_lock is used to ensure that MFP register configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * (most likely a read-modify-write operation) is atomic, and that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * mfp_table[] is consistent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static DEFINE_SPINLOCK(mfp_spin_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static void __iomem *mfpr_mmio_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct mfp_pin {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) unsigned long config; /* -1 for not configured */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) unsigned long mfpr_off; /* MFPRxx Register offset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) unsigned long mfpr_run; /* Run-Mode Register Value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned long mfpr_lpm; /* Low Power Mode Register Value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static struct mfp_pin mfp_table[MFP_PIN_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static const unsigned long mfpr_lpm[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) MFPR_LPM_INPUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) MFPR_LPM_DRIVE_LOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) MFPR_LPM_DRIVE_HIGH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) MFPR_LPM_PULL_LOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) MFPR_LPM_PULL_HIGH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) MFPR_LPM_FLOAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) MFPR_LPM_INPUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static const unsigned long mfpr_pull[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) MFPR_PULL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) MFPR_PULL_LOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) MFPR_PULL_HIGH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) MFPR_PULL_BOTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) MFPR_PULL_FLOAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static const unsigned long mfpr_edge[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) MFPR_EDGE_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) MFPR_EDGE_RISE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) MFPR_EDGE_FALL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) MFPR_EDGE_BOTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define mfpr_readl(off) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) __raw_readl(mfpr_mmio_base + (off))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define mfpr_writel(off, val) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) __raw_writel(val, mfpr_mmio_base + (off))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define mfp_configured(p) ((p)->config != -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * perform a read-back of any valid MFPR register to make sure the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * previous writings are finished
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static unsigned long mfpr_off_readback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + mfpr_off_readback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static inline void __mfp_config_run(struct mfp_pin *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (mfp_configured(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) mfpr_writel(p->mfpr_off, p->mfpr_run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static inline void __mfp_config_lpm(struct mfp_pin *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (mfp_configured(p)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (mfpr_clr != p->mfpr_run)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) mfpr_writel(p->mfpr_off, mfpr_clr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (p->mfpr_lpm != mfpr_clr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) mfpr_writel(p->mfpr_off, p->mfpr_lpm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) void mfp_config(unsigned long *mfp_cfgs, int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) spin_lock_irqsave(&mfp_spin_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) for (i = 0; i < num; i++, mfp_cfgs++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) unsigned long tmp, c = *mfp_cfgs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct mfp_pin *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) int pin, af, drv, lpm, edge, pull;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) pin = MFP_PIN(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) BUG_ON(pin >= MFP_PIN_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) p = &mfp_table[pin];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) af = MFP_AF(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) drv = MFP_DS(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) lpm = MFP_LPM_STATE(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) edge = MFP_LPM_EDGE(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) pull = MFP_PULL(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /* run-mode pull settings will conflict with MFPR bits of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * low power mode state, calculate mfpr_run and mfpr_lpm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * individually if pull != MFP_PULL_NONE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (likely(pull == MFP_PULL_NONE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) p->mfpr_lpm = p->mfpr_run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) p->mfpr_run = tmp | mfpr_pull[pull];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) p->config = c; __mfp_config_run(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) mfpr_sync();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) spin_unlock_irqrestore(&mfp_spin_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) unsigned long mfp_read(int mfp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) unsigned long val, flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) BUG_ON(mfp < 0 || mfp >= MFP_PIN_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) spin_lock_irqsave(&mfp_spin_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) val = mfpr_readl(mfp_table[mfp].mfpr_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) spin_unlock_irqrestore(&mfp_spin_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) void mfp_write(int mfp, unsigned long val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) BUG_ON(mfp < 0 || mfp >= MFP_PIN_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) spin_lock_irqsave(&mfp_spin_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) mfpr_writel(mfp_table[mfp].mfpr_off, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) mfpr_sync();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) spin_unlock_irqrestore(&mfp_spin_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) void __init mfp_init_base(void __iomem *mfpr_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /* initialize the table with default - unconfigured */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) for (i = 0; i < ARRAY_SIZE(mfp_table); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) mfp_table[i].config = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) mfpr_mmio_base = mfpr_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) void __init mfp_init_addr(struct mfp_addr_map *map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct mfp_addr_map *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) unsigned long offset, flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) spin_lock_irqsave(&mfp_spin_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /* mfp offset for readback */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) mfpr_off_readback = map[0].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) for (p = map; p->start != MFP_PIN_INVALID; p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) offset = p->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) i = p->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) mfp_table[i].mfpr_off = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) mfp_table[i].mfpr_run = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) mfp_table[i].mfpr_lpm = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) offset += 4; i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) } while ((i <= p->end) && (p->end != -1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) spin_unlock_irqrestore(&mfp_spin_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) void mfp_config_lpm(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct mfp_pin *p = &mfp_table[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) int pin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) __mfp_config_lpm(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) void mfp_config_run(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) struct mfp_pin *p = &mfp_table[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) int pin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) __mfp_config_run(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }