mpp.c 3.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * arch/arm/mach-orion5x/mpp.c
 *
 * MPP functions for Marvell Orion 5x SoCs
 *
 * 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.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mbus.h>
14
#include <mach/hardware.h>
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
#include <asm/io.h>
#include "common.h"
#include "mpp.h"

static int is_5181l(void)
{
	u32 dev;
	u32 rev;

	orion5x_pcie_id(&dev, &rev);

	return !!(dev == MV88F5181_DEV_ID && rev >= MV88F5181L_REV_A0);
}

static int is_5182(void)
{
	u32 dev;
	u32 rev;

	orion5x_pcie_id(&dev, &rev);

	return !!(dev == MV88F5182_DEV_ID);
}

static int is_5281(void)
{
	u32 dev;
	u32 rev;

	orion5x_pcie_id(&dev, &rev);

	return !!(dev == MV88F5281_DEV_ID);
}

static int __init determine_type_encoding(int mpp, enum orion5x_mpp_type type)
{
	switch (type) {
	case MPP_UNUSED:
	case MPP_GPIO:
		if (mpp == 0)
			return 3;
		if (mpp >= 1 && mpp <= 15)
			return 0;
		if (mpp >= 16 && mpp <= 19) {
			if (is_5182())
				return 5;
			if (type == MPP_UNUSED)
				return 0;
		}
		return -1;

	case MPP_PCIE_RST_OUTn:
		if (mpp == 0)
			return 0;
		return -1;

	case MPP_PCI_ARB:
		if (mpp >= 0 && mpp <= 7)
			return 2;
		return -1;

	case MPP_PCI_PMEn:
		if (mpp == 2)
			return 3;
		return -1;

	case MPP_GIGE:
		if (mpp >= 8 && mpp <= 19)
			return 1;
		return -1;

	case MPP_NAND:
		if (is_5182() || is_5281()) {
			if (mpp >= 4 && mpp <= 7)
				return 4;
			if (mpp >= 12 && mpp <= 17)
				return 4;
		}
		return -1;

	case MPP_PCI_CLK:
		if (is_5181l() && mpp >= 6 && mpp <= 7)
			return 5;
		return -1;

	case MPP_SATA_LED:
		if (is_5182()) {
			if (mpp >= 4 && mpp <= 7)
				return 5;
			if (mpp >= 12 && mpp <= 15)
				return 5;
		}
		return -1;

	case MPP_UART:
		if (mpp >= 16 && mpp <= 19)
			return 0;
		return -1;
	}

	printk(KERN_INFO "unknown MPP type %d\n", type);

	return -1;
}

void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
{
	u32 mpp_0_7_ctrl = readl(MPP_0_7_CTRL);
	u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL);
	u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL);

	while (mode->mpp >= 0) {
		u32 *reg;
		int num_type;
		int shift;

		if (mode->mpp >= 0 && mode->mpp <= 7)
			reg = &mpp_0_7_ctrl;
		else if (mode->mpp >= 8 && mode->mpp <= 15)
			reg = &mpp_8_15_ctrl;
		else if (mode->mpp >= 16 && mode->mpp <= 19)
			reg = &mpp_16_19_ctrl;
		else {
			printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
					"(%d)\n", mode->mpp);
			continue;
		}

		num_type = determine_type_encoding(mode->mpp, mode->type);
		if (num_type < 0) {
			printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
					"combination (%d, %d)\n", mode->mpp,
					mode->type);
			continue;
		}

		shift = (mode->mpp & 7) << 2;
		*reg &= ~(0xf << shift);
		*reg |= (num_type & 0xf) << shift;

		orion5x_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));

		mode++;
	}

	writel(mpp_0_7_ctrl, MPP_0_7_CTRL);
	writel(mpp_8_15_ctrl, MPP_8_15_CTRL);
	writel(mpp_16_19_ctrl, MPP_16_19_CTRL);
}