linux/arch/arm/mach-orion5x/mpp.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-orion5x/mpp.c
   3 *
   4 * MPP functions for Marvell Orion 5x SoCs
   5 *
   6 * This file is licensed under the terms of the GNU General Public
   7 * License version 2.  This program is licensed "as is" without any
   8 * warranty of any kind, whether express or implied.
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/init.h>
  13#include <linux/mbus.h>
  14#include <mach/hardware.h>
  15#include <asm/io.h>
  16#include "common.h"
  17#include "mpp.h"
  18
  19static int is_5181l(void)
  20{
  21        u32 dev;
  22        u32 rev;
  23
  24        orion5x_pcie_id(&dev, &rev);
  25
  26        return !!(dev == MV88F5181_DEV_ID && rev >= MV88F5181L_REV_A0);
  27}
  28
  29static int is_5182(void)
  30{
  31        u32 dev;
  32        u32 rev;
  33
  34        orion5x_pcie_id(&dev, &rev);
  35
  36        return !!(dev == MV88F5182_DEV_ID);
  37}
  38
  39static int is_5281(void)
  40{
  41        u32 dev;
  42        u32 rev;
  43
  44        orion5x_pcie_id(&dev, &rev);
  45
  46        return !!(dev == MV88F5281_DEV_ID);
  47}
  48
  49static int __init determine_type_encoding(int mpp, enum orion5x_mpp_type type)
  50{
  51        switch (type) {
  52        case MPP_UNUSED:
  53        case MPP_GPIO:
  54                if (mpp == 0)
  55                        return 3;
  56                if (mpp >= 1 && mpp <= 15)
  57                        return 0;
  58                if (mpp >= 16 && mpp <= 19) {
  59                        if (is_5182())
  60                                return 5;
  61                        if (type == MPP_UNUSED)
  62                                return 0;
  63                }
  64                return -1;
  65
  66        case MPP_PCIE_RST_OUTn:
  67                if (mpp == 0)
  68                        return 0;
  69                return -1;
  70
  71        case MPP_PCI_ARB:
  72                if (mpp >= 0 && mpp <= 7)
  73                        return 2;
  74                return -1;
  75
  76        case MPP_PCI_PMEn:
  77                if (mpp == 2)
  78                        return 3;
  79                return -1;
  80
  81        case MPP_GIGE:
  82                if (mpp >= 8 && mpp <= 19)
  83                        return 1;
  84                return -1;
  85
  86        case MPP_NAND:
  87                if (is_5182() || is_5281()) {
  88                        if (mpp >= 4 && mpp <= 7)
  89                                return 4;
  90                        if (mpp >= 12 && mpp <= 17)
  91                                return 4;
  92                }
  93                return -1;
  94
  95        case MPP_PCI_CLK:
  96                if (is_5181l() && mpp >= 6 && mpp <= 7)
  97                        return 5;
  98                return -1;
  99
 100        case MPP_SATA_LED:
 101                if (is_5182()) {
 102                        if (mpp >= 4 && mpp <= 7)
 103                                return 5;
 104                        if (mpp >= 12 && mpp <= 15)
 105                                return 5;
 106                }
 107                return -1;
 108
 109        case MPP_UART:
 110                if (mpp >= 16 && mpp <= 19)
 111                        return 0;
 112                return -1;
 113        }
 114
 115        printk(KERN_INFO "unknown MPP type %d\n", type);
 116
 117        return -1;
 118}
 119
 120void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
 121{
 122        u32 mpp_0_7_ctrl = readl(MPP_0_7_CTRL);
 123        u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL);
 124        u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL);
 125
 126        while (mode->mpp >= 0) {
 127                u32 *reg;
 128                int num_type;
 129                int shift;
 130
 131                if (mode->mpp >= 0 && mode->mpp <= 7)
 132                        reg = &mpp_0_7_ctrl;
 133                else if (mode->mpp >= 8 && mode->mpp <= 15)
 134                        reg = &mpp_8_15_ctrl;
 135                else if (mode->mpp >= 16 && mode->mpp <= 19)
 136                        reg = &mpp_16_19_ctrl;
 137                else {
 138                        printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
 139                                        "(%d)\n", mode->mpp);
 140                        continue;
 141                }
 142
 143                num_type = determine_type_encoding(mode->mpp, mode->type);
 144                if (num_type < 0) {
 145                        printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
 146                                        "combination (%d, %d)\n", mode->mpp,
 147                                        mode->type);
 148                        continue;
 149                }
 150
 151                shift = (mode->mpp & 7) << 2;
 152                *reg &= ~(0xf << shift);
 153                *reg |= (num_type & 0xf) << shift;
 154
 155                orion5x_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));
 156
 157                mode++;
 158        }
 159
 160        writel(mpp_0_7_ctrl, MPP_0_7_CTRL);
 161        writel(mpp_8_15_ctrl, MPP_8_15_CTRL);
 162        writel(mpp_16_19_ctrl, MPP_16_19_CTRL);
 163}
 164