[RFC PATCH] drivers/pinctrl: Add pinctrl-ast2400

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add pinctrl/pinmux support for the Aspeed AST2400 SoC. Configuration of
the SoC is somewhat involved: Enabling functions can involve writes of
multiple bits to multiple registers, and signals provided by a pin are
determined on a priority basis. That is, without care, it's possible to
configure a function in the mux and to not gain expected functionality.

Signed-off-by: Andrew Jeffery <andrew@xxxxxxxx>
---
 drivers/pinctrl/pinctrl-ast2400.c | 1488 +++++++++++++++++++++++++++++++++++++
 1 file changed, 1488 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-ast2400.c

diff --git a/drivers/pinctrl/pinctrl-ast2400.c b/drivers/pinctrl/pinctrl-ast2400.c
new file mode 100644
index 000000000000..0f0c19005046
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ast2400.c
@@ -0,0 +1,1488 @@
+/*
+ * Copyright (C) 2016 IBM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "core.h"
+#include "pinctrl-utils.h"
+
+/* Challenges in the AST2400 Multifunction Pin Design
+ * --------------------------------------------------
+ *
+ * * Reasonable number of pins (216)
+ *
+ * * The SoC function enabled on a pin is determined on a priority basis
+ *
+ * * Using the priority system, pins can provide up to 3 different signals
+ *   types
+ *
+ * * The signal active on a pin is often described by compound logical
+ *   expressions involving multiple operators, registers and bits
+ *
+ *   * The high and low priority functions' bit masks are frequently not the
+ *     same
+ *     (i.e. cannot just flip a bit to change from high to low), or even in the
+ *     same register.
+ *
+ *   * Not all functions are disabled by unsetting bits, some require setting
+ *     bits
+ *
+ *   * Not all signals can be deactivated as some expressions depend on values
+ *     in the hardware strapping register, which is treated as read-only.
+ *
+ * SoC Multi-function Pin Expression Examples
+ * ------------------------------------------
+ *
+ * Here are some sample mux configurations from the datasheet to illustrate the
+ * corner cases, roughly in order of least to most corner. In the table, HP and
+ * LP are high- and low- priority respectively.
+ *
+ * D6 is a pin with a single (i.e. aside from GPIO), high priority signal
+ * that participates in one function:
+ *
+ * Ball | Default | HP Signal | HP Expression               | LP Signal | LP Expression | GPIO Name
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *  D6    GPIOA0    MAC1LINK    SCU80[0]=1                                                GPIOA0
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * C5 is a multi-signal pin (both high and low priority signals). Here we touch
+ * different registers for the different functions that enable each signal:
+ *
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *  C5    GPIOA4    SCL9        SCU90[22]=1                   TIMER5      SCU80[4]=1      GPIOA4
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * E19 is a single-signal pin with two functions that influence the active
+ * signal. In this case both bits have the same meaning - enable a dedicated
+ * LPC reset pin. However it's not always the case that the bits in the
+ * OR-relationship have the same meaning.
+ *
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *  E19   GPIOB4    LPCRST#     SCU80[12]=1 | Strap[14]=1                                 GPIOB4
+ * -----+---------+-----------+-----------------------------+-----------+---------------+----------
+ *
+ * For example, pin B19 has a low-priority signal that's enabled by two
+ * distinct SoC functions: A specific SIOPBI bit in SCUA4, and an ACPI bit
+ * in the STRAP register. The ACPI bit configures signals on pins in addition
+ * to B19. Both of the low priority functions as well as the high priority
+ * function must be disabled for GPIOF1 to be used.
+ *
+ * Ball | Default | HP Signal | HP Expression                           | LP Signal | LP Expression                          | GPIO Name
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *  B19   GPIOF1    NDCD4       SCU80[25]=1                               SIOPBI#     SCUA4[12]=1 | Strap[19]=0                GPIOF1
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *
+ * For pin E18, the SoC ANDs the expected state of three bits to determine the
+ * pin's active signal:
+ *
+ * * SCU3C[3]: Enable external SOC reset function
+ * * SCU80[15]: Enable SPICS1# or EXTRST# function pin
+ * * SCU90[31]: Select SPI interface CS# output
+ *
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *  E18   GPIOB7    EXTRST#     SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=0    SPICS1#     SCU3C[3]=1 & SCU80[15]=1 & SCU90[31]=1   GPIOB7
+ * -----+---------+-----------+-----------------------------------------+-----------+----------------------------------------+----------
+ *
+ * (Bits SCU3C[3] and SCU80[15] appear to only be used in the expressions for
+ * selecting the signals on pin E18)
+ *
+ * Pin T5 is a multi-signal pin with a more complex configuration:
+ *
+ * Ball | Default | HP Signal | HP Expression                | LP Signal | LP Expression | GPIO Name
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *  T5    GPIOL1    VPIDE       SCU90[5:4]!=0 & SCU84[17]=1    NDCD1       SCU84[17]=1     GPIOL1
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * The high priority signal configuration is best thought of in terms of its
+ * exploded form, with reference to the SCU90[5:4] bits:
+ *
+ * * SCU90[5:4]=00: disable
+ * * SCU90[5:4]=01: 18 bits (R6/G6/B6) video mode.
+ * * SCU90[5:4]=10: 24 bits (R8/G8/B8) video mode.
+ * * SCU90[5:4]=11: 30 bits (R10/G10/B10) video mode.
+ *
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *  T5    GPIOL1    VPIDE      (SCU90[5:4]=1 & SCU84[17]=1)    NDCD1       SCU84[17]=1     GPIOL1
+ *                             | (SCU90[5:4]=2 & SCU84[17]=1)
+ *                             | (SCU90[5:4]=3 & SCU84[17]=1)
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * For reference the SCU84[17] bit enables the "UART1 NDCD1 or Video VPIDE
+ * function pin", where the signal itself is determined by whether SCU94[5:4]
+ * is disabled or in one of the 18, 24 or 30bit video modes.
+ *
+ * Other video-input-related pins require an explicit state in SCU90[5:4]:
+ *
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *  W1    GPIOL6    VPIB0       SCU90[5:4]=3 & SCU84[22]=1     TXD1        SCU84[22]=1     GPIOL6
+ * -----+---------+-----------+------------------------------+-----------+---------------+----------
+ *
+ * The examples of T5 and W1 are particularly fertile, as they also demonstrate
+ * that despite operating as part of the video input bus each signal needs to
+ * be enabled individually via it's own SCU84 (in the cases of T5 and W1)
+ * register bit. This is a little crazy if the bus doesn't have optional
+ * signals, but is used to decent effect with some of the UARTs where not all
+ * signals are required. However, this isn't done consistently - UART1 is
+ * enabled on a per-pin basis, and by contrast, all signals for UART6 are
+ * enabled by a single bit.
+ *
+ * Ultimately the requirement to control pins like T5 drive the design:
+ *
+ * * Pins provide signals according to functions activated in the mux
+ *   configuration
+ *
+ * * Pins provide two to three signals in a priority order
+ *
+ * * For priorities levels defined on a pin, each priority provides one signal
+ *
+ * * Enabling lower priority signals requires higher priority signals be
+ *   disabled
+ *
+ * * A function represents a set of signals; functions are distinct if their
+ *   sets of signals are not equal
+ *
+ * * Signals participate in one or more functions
+ *
+ * * A function is described by an expression of one or more function
+ *   descriptors, which compare bit values in a register
+ *
+ * * A function expression is the smallest set of function descriptors whose
+ *   comparisons must evaluate 'true' for a function to be enabled.
+ *
+ * * A function is active if evaluating every function descriptor in the
+ *   function expression yields a 'true' result
+ *
+ * * A signal at a given priority on a given pin is active if any of the
+ *   functions in which the signal participates are active, and no higher
+ *   priority signal on the pin is active
+ *
+ * * GPIO is configured per-pin
+ *
+ * And so:
+ *
+ * * To disable a signal, any function(s) activating the signal must be
+ *   disabled
+ *
+ * * Each pin must know the expressions of functions in which it participates,
+ *   for the purpose of enabling GPIO. This is done by deactivating all
+ *   functions that activate higher priority signals on the pin (except in the
+ *   case of GPIO[TUV], where GPIO is the high priority function).
+ *
+ * As a concrete example:
+ *
+ * * T5 provides three signals types: VPIDE, NDCD1 and GPIO
+ *
+ * * The VPIDE signal participates in 3 functions: VPI18, VPI24 and VPI30
+ *
+ * * The NDCD1 signal participates in just its own NDCD1 function
+ *
+ * * VPIDE is high priority, NDCD1 is low priority, and GPIOL1 is the least
+ *   prioritised
+ *
+ * * The prerequisit for activating the NDCD1 signal is that the VPI18, VPI24
+ *   and VPI30 functions all be disabled
+ *
+ * * Similarly, all of VPI18, VPI24, VPI30 and NDCD1 functions must be disabled
+ *   to provide GPIOL6
+ *
+ * Considerations
+ * --------------
+ *
+ * * If pinctrl allows us to allocate a pin we can configure a function without
+ *   concern for the function of already allocated pins, if pin groups are
+ *   created with respect to the SoC functions in which they participate (I felt
+ *   this was worth mentioning as it didn't seem obvious from the bit/pin
+ *   relationships; I've done some network analysis on the problem).
+ *
+ *     * Conversely, failing to allocate all pins in a group indicates some
+ *       bits (as well as pins) required for the group's configuration will
+ *       already be in use, likely in a way that's inconsistent with the
+ *       requirements of the failed group.
+ *
+ * * Implement data structures such that we can lean on the compiler to avoid
+ *   or catch errors
+ *
+ *   * Define symbols for structures so they can be referenced by name
+ *
+ *     * Compiler enforces unique symbol names, detecting copy/paste errors
+ *     * Compiler errors on undefined symbol names, detecting typos or missing
+ *       information
+ *
+ *   * Compiler can calculate array sizes for us
+ *
+ * * Implement macros such that we can lean on the CPP to
+ *
+ *   * Avoid duplicate specification of information where possible
+ *   * Reduce line noise of type declaration and assignment
+ */
+
+ /**
+  * A function descriptor, which describes the register, bits and the
+  * enable/disable values that should be compared or written.
+  *
+  * @reg: The register offset from base in bytes
+  * @mask: The mask to apply to the register. The lowest set bit of the mask is
+  *        used to derive the shift value.
+  * @enable: The value that enables the function. Value should be in the LSBs,
+  *          not at the position of the mask.
+  * @disable: The value that disables the function. Value should be in the
+  *           LSBs, not at the position of the mask.
+  */
+struct func_desc {
+	unsigned reg;
+	u32 mask;
+	u32 enable;
+	u32 disable;
+};
+
+/**
+ * Describes a function expression. The expression is evaluated by ANDing the
+ * evaluation of the descriptors.
+ *
+ * @name: The function name
+ * @ndescs: The number of function descriptors in the expression
+ * @descs: Pointer to an array of function descriptors that comprise the
+ *         function expression
+ */
+struct func_expr {
+	const char *name;
+	int ndescs;
+	const struct func_desc *descs;
+};
+
+/**
+ * A struct capturing the function expressions enabling signals at each
+ * priority for a given pin. A high or low priority signal configuration is
+ * evaluated by ORing the evaluation of the function expressions in the
+ * respective priority's list.
+ *
+ * @high: A NULL-terminated list of function expressions that enable the
+ *        high-priority signal
+ * @low: A NULL-terminated list of function expressions that enable the
+ *       low-priority signal
+ * @other: The name of the "other" function, enabled by disabling the high and
+ *         low priority signals
+ */
+struct pin_prio {
+	const struct func_expr **high;
+	const struct func_expr **low;
+	const char *other;
+};
+
+/* Macro hell */
+
+/**
+ * Short-hand macro describing a mux function enabled by the state of one bit.
+ * The disable value is derived.
+ *
+ * @reg: The function's associated register, offset from base
+ * @idx: The function's bit index in the register
+ * @val: The value (0 or 1) that enables the function
+ */
+#define FUNC_DESC_BIT(reg, idx, val) \
+	{ reg, BIT_MASK(idx), val, ((val + 1) & 1) }
+
+/**
+ * A further short-hand macro describing a mux function enabled with a set bit.
+ *
+ * @reg: The function's associated register, offset from base
+ * @idx: The function's bit index in the register
+ */
+#define FUNC_DESC_SET(reg, idx) FUNC_DESC_BIT(reg, idx, 1)
+
+#define FUNC_DESC_LIST_SYM(func) func_descs_ ## func
+#define FUNC_DESC_LIST_DECL(func, ...) \
+	static const struct func_desc FUNC_DESC_LIST_SYM(func)[] = \
+		{ __VA_ARGS__ }
+
+#define FUNC_EXPR_SYM(func) func_expr_ ## func
+#define FUNC_EXPR_DECL_(func) \
+	static const struct func_expr FUNC_EXPR_SYM(func) = \
+	{ \
+		.name = #func, \
+		.ndescs = ARRAY_SIZE(FUNC_DESC_LIST_SYM(func)), \
+		.descs = &(FUNC_DESC_LIST_SYM(func))[0], \
+	}
+
+/**
+ * Declare a function expression.
+ *
+ * @func: A macro symbol name for the function (is subjected to stringification
+ *        and token pasting)
+ * @...: Function descriptors that define the function expression
+ *
+ * For example, the following declares the ACPI function:
+ *
+ *     FUNC_EXPR_DECL(ACPI, FUNC_DESC_BIT(STRAP, 19, 0));
+ *
+ * And (with a few defines left out for brevity) the following declares the
+ * 8-signal ROM function:
+ *
+ *     FUNC_EXPR_DECL(ROM8,
+ *         VPOOFF0_DESC,
+ *         ROMEN_0_DESC,
+ *         ROMEN_1_DESC,
+ *         ROMEN_2_DESC);
+ */
+#define FUNC_EXPR_DECL(func, ...) \
+	FUNC_DESC_LIST_DECL(func, __VA_ARGS__); \
+	FUNC_EXPR_DECL_(func)
+
+/**
+ * Declare a pointer to a function expression
+ *
+ * @func: The macro symbol name for the function (subjected to token pasting)
+ */
+#define FUNC_EXPR_PTR(func) (&FUNC_EXPR_SYM(func))
+
+#define FUNC_EXPR_LIST_SYM(func) func_exprs_ ## func
+
+/**
+ * Declare a function list for reference in a struct pin_prio.
+ *
+ * @func: A macro symbol name for the function (is subjected to token pasting)
+ * @...: Function expression structure pointers (use FUNC_EXPR_POINTER())
+ */
+#define FUNC_EXPR_LIST_DECL(func, ...) \
+	const struct func_expr *FUNC_EXPR_LIST_SYM(func)[] = { __VA_ARGS__ }
+
+/**
+ * A short-hand macro for declaring an expression list consisting of a single
+ * function.
+ *
+ * @func: A macro symbol name for the function (is subjected to token pasting)
+ */
+#define FUNC_EXPR_LIST_DECL_SINGLE(func) \
+	FUNC_EXPR_LIST_DECL(func, FUNC_EXPR_PTR(func), NULL)
+
+#define FUNC_EXPR_LIST_PTR(func) (&FUNC_EXPR_LIST_SYM(func)[0])
+
+/**
+ * A short-hand macro for declaring a function expression and an expression
+ * list with a single function.
+ *
+ * @func: A macro symbol name for the function (is subjected to token pasting)
+ * @...: Function descriptors that define the function expression
+ */
+#define FUNC_EXPR_DECL_SINGLE(func, ...) \
+	FUNC_DESC_LIST_DECL(func, __VA_ARGS__); \
+	FUNC_EXPR_DECL_(func); \
+	FUNC_EXPR_LIST_DECL(func, FUNC_EXPR_PTR(func), NULL)
+
+#define PIN_SYM(pin) pin_ ## pin
+
+#define MS_PIN_DECL_(pin, other, high, low) \
+	static const struct pin_prio PIN_SYM(pin) = { high, low, #other }
+
+/**
+ * Declare a multi-signal pin
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @high: Macro name for the high signal functions
+ * @low: Macro name for the low signal functions
+ *
+ * For example:
+ *
+ *    FUNC_EXPR_DECL_SINGLE(SD1, FUNC_DESC_SET(SCU90, 0));
+ *    FUNC_EXPR_DECL_SINGLE(I2C10, FUNC_DESC_SET(SCU90, 23));
+ *
+ *    #define C4 16
+ *    MS_PIN_DECL(C4, GPIOC0, SD1, I2C10);
+ *    #define B3 17
+ *    MS_PIN_DECL(B3, GPIOC1, SD1, I2C10);
+ */
+#define MS_PIN_DECL(pin, other, high, low) \
+	MS_PIN_DECL_(pin, other, \
+			FUNC_EXPR_LIST_PTR(high), \
+			FUNC_EXPR_LIST_PTR(low))
+
+#define PIN_GROUP_SYM(func) pins_ ## func
+#define FUNC_GROUP_SYM(func) groups_ ## func
+#define FUNC_GROUP_DECL(func, ...) \
+	static const int PIN_GROUP_SYM(func)[] = { __VA_ARGS__ }; \
+	static const char *const FUNC_GROUP_SYM(func)[] = { #func }
+
+/**
+ * Declare a single signal pin
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @func: Macro name for the function
+ *
+ * For example:
+ *
+ *    FUNC_EXPR_DECL_SINGLE(I2C5, FUNC_DESC_SET(SCU90, 18));
+ *
+ *    #define E3 80
+ *    SS_PIN_DECL(E3, GPIOK0, I2C5);
+ *
+ *    #define D2 81
+ *    SS_PIN_DECL(D2, GPIOK1, I2C5);
+ */
+#define SS_PIN_DECL(pin, other, func) \
+	MS_PIN_DECL_(pin, other, FUNC_EXPR_LIST_PTR(func), NULL)
+
+/**
+ * Single signal, single function pin declaration
+ *
+ * @pin: The pin number
+ * @other: Macro name for "other" functionality (subjected to stringification)
+ * @func: Macro name for the function
+ * @...: Function descriptors that define the function expression
+ *
+ * For example:
+ *
+ *    SSSF_PIN_DECL(A4, GPIOA2, TIMER3, FUNC_DESC_SET(SCU80, 2));
+ */
+#define SSSF_PIN_DECL(pin, other, func, ...) \
+	FUNC_EXPR_DECL(func, __VA_ARGS__); \
+	FUNC_EXPR_LIST_DECL(func, FUNC_EXPR_PTR(func), NULL); \
+	MS_PIN_DECL_(pin, other, FUNC_EXPR_LIST_PTR(func), NULL); \
+	FUNC_GROUP_DECL(func, pin)
+
+#define SCU3C 0x3C
+#define STRAP 0x70
+#define SCU80 0x80
+#define SCU84 0x84
+#define SCU88 0x88
+#define SCU8C 0x8C
+#define SCU90 0x90
+#define SCU94 0x94
+#define SCUA4 0xA4
+
+/* Use undefined macros for symbol naming and references, eg GPIOA0, MAC1LINK,
+ * TIMER3 etc.
+ */
+
+/* Pins are defined in GPIO bank order:
+ *
+ * GPIOA0: 0
+ * ...
+ * GPIOA7: 7
+ * ...
+ * GPIOB0: 8
+ * ...
+ * GPIOZ7: 207
+ * GPIOAA0: 208
+ * ...
+ * GPIOAB3: 219
+ *
+ * Not all pins have their signals defined.
+ */
+
+#define A4 2
+SSSF_PIN_DECL(A4, GPIOA2, TIMER3, FUNC_DESC_SET(SCU80, 2));
+
+FUNC_EXPR_DECL_SINGLE(SD1, FUNC_DESC_SET(SCU90, 0));
+
+FUNC_EXPR_DECL_SINGLE(I2C10, FUNC_DESC_SET(SCU90, 23));
+
+#define C4 16
+MS_PIN_DECL(C4, GPIOC0, SD1, I2C10);
+#define B3 17
+MS_PIN_DECL(B3, GPIOC1, SD1, I2C10);
+
+FUNC_GROUP_DECL(I2C10, C4, B3);
+
+FUNC_EXPR_DECL_SINGLE(I2C11, FUNC_DESC_SET(SCU90, 24));
+
+#define A2 18
+MS_PIN_DECL(A2, GPIOC2, SD1, I2C11);
+#define E5 19
+MS_PIN_DECL(E5, GPIOC3, SD1, I2C11);
+
+FUNC_GROUP_DECL(I2C11, A2, E5);
+
+FUNC_EXPR_DECL_SINGLE(I2C12, FUNC_DESC_SET(SCU90, 25));
+
+#define D4 20
+MS_PIN_DECL(D4, GPIOC4, SD1, I2C12);
+#define C3 21
+MS_PIN_DECL(C3, GPIOC5, SD1, I2C12);
+
+FUNC_GROUP_DECL(I2C12, D4, C3);
+
+FUNC_EXPR_DECL_SINGLE(I2C13, FUNC_DESC_SET(SCU90, 26));
+
+#define B2 22
+MS_PIN_DECL(B2, GPIOC6, SD1, I2C13);
+#define A1 23
+MS_PIN_DECL(A1, GPIOC7, SD1, I2C13);
+
+FUNC_GROUP_DECL(I2C13, B2, A1);
+FUNC_GROUP_DECL(SD1, C4, B3, A2, E5, D4, C3, B2, A1);
+
+#define D18 40
+SSSF_PIN_DECL(D18, GPIOF0, NCTS4, FUNC_DESC_SET(SCU80, 24));
+
+FUNC_EXPR_DECL(ACPI, FUNC_DESC_BIT(STRAP, 19, 0));
+
+#define B19 41
+FUNC_EXPR_DECL(NDCD4, FUNC_DESC_SET(SCU80, 25));
+FUNC_EXPR_LIST_DECL_SINGLE(NDCD4);
+FUNC_EXPR_DECL(SIOPBI, FUNC_DESC_SET(SCUA4, 12));
+FUNC_EXPR_LIST_DECL(SIOPBI, FUNC_EXPR_PTR(SIOPBI), FUNC_EXPR_PTR(ACPI), NULL);
+MS_PIN_DECL(B19, GPIOF1, NDCD4, SIOPBI);
+FUNC_GROUP_DECL(NDCD4, B19);
+FUNC_GROUP_DECL(SIOPBI, B19);
+
+#define D17 43
+FUNC_EXPR_DECL(NRI4, FUNC_DESC_SET(SCU80, 27));
+FUNC_EXPR_LIST_DECL_SINGLE(NRI4);
+FUNC_EXPR_DECL(SIOPBO, FUNC_DESC_SET(SCUA4, 14));
+FUNC_EXPR_LIST_DECL(SIOPBO, FUNC_EXPR_PTR(SIOPBO), FUNC_EXPR_PTR(ACPI), NULL);
+MS_PIN_DECL(D17, GPIOF3, NRI4, SIOPBO);
+FUNC_GROUP_DECL(NRI4, D17);
+FUNC_GROUP_DECL(SIOPBO, D17);
+
+FUNC_GROUP_DECL(ACPI, B19, D17);
+
+#define E16 46
+SSSF_PIN_DECL(E16, GPIOF6, TXD4, FUNC_DESC_SET(SCU80, 30));
+
+#define C17 47
+SSSF_PIN_DECL(C17, GPIOF7, RXD4, FUNC_DESC_SET(SCU80, 31));
+
+#define AA22 54
+SSSF_PIN_DECL(AA22, GPIOG6, FLBUSY, FUNC_DESC_SET(SCU84, 6));
+
+#define U18 55
+SSSF_PIN_DECL(U18, GPIOG7, FLWP, FUNC_DESC_SET(SCU84, 7));
+
+/* The following descriptors describe incomplete list of signals for VPO/ROM,
+ * enough to cover the pins which we need to configure in the OpenPOWER
+ * Palmetto BMC. Some functions require separate functions be disabled, so
+ * we're describing masks for those separate functions and setting the enabled
+ * value to the disabled value. Also, GENMASK() is used to require a range of
+ * set bits, where each signal has its own activation bit rather than all being
+ * activated by a single bit.
+ */
+#define VPOOFF0_DESC { SCU94, GENMASK(1, 0), 0, 0 }
+#define ROMEN_0_DESC \
+	{ SCU88, GENMASK(29, 24), GENMASK(5, 0), 0 }
+#define ROMEN_1_DESC \
+	{ SCU8C, GENMASK(7, 0), GENMASK(7, 0), 0 }
+#define ROMEN_2_DESC { SCU94, BIT_MASK(1), 0, 0 }
+#define ROMEN_3_DESC \
+	{ STRAP, GENMASK(1, 0), 0, 0 }
+
+FUNC_EXPR_DECL(ROM8,
+		VPOOFF0_DESC,
+		ROMEN_0_DESC,
+		ROMEN_1_DESC,
+		ROMEN_2_DESC);
+
+/* ROM16 enabled by SCU90 */
+FUNC_EXPR_DECL(ROM16,
+		VPOOFF0_DESC,
+		ROMEN_0_DESC,
+		ROMEN_1_DESC,
+		ROMEN_2_DESC,
+		FUNC_DESC_SET(SCU90, 6));
+
+/* ROM16 enabled by strapping register */
+FUNC_EXPR_DECL(ROM16S,
+		VPOOFF0_DESC,
+		ROMEN_0_DESC,
+		ROMEN_1_DESC,
+		ROMEN_2_DESC,
+		FUNC_DESC_SET(STRAP, 4),
+		ROMEN_3_DESC);
+
+FUNC_EXPR_LIST_DECL(ROM16,
+		FUNC_EXPR_PTR(ROM16),
+		FUNC_EXPR_PTR(ROM16S),
+		NULL);
+
+FUNC_EXPR_DECL_SINGLE(UART6, FUNC_DESC_SET(SCU90, 7));
+
+#define A8 56
+MS_PIN_DECL(A8, GPIOH0, ROM16, UART6);
+
+#define C7 57
+MS_PIN_DECL(C7, GPIOH1, ROM16, UART6);
+
+#define B7 58
+MS_PIN_DECL(B7, GPIOH2, ROM16, UART6);
+
+#define A7 59
+MS_PIN_DECL(A7, GPIOH3, ROM16, UART6);
+
+#define D7 60
+MS_PIN_DECL(D7, GPIOH4, ROM16, UART6);
+
+#define B6 61
+MS_PIN_DECL(B6, GPIOH5, ROM16, UART6);
+
+#define A6 62
+MS_PIN_DECL(A6, GPIOH6, ROM16, UART6);
+
+#define E7 63
+MS_PIN_DECL(E7, GPIOH7, ROM16, UART6);
+
+FUNC_GROUP_DECL(UART6, A8, C7, B7, A7, D7, B6, A6, E7);
+
+#define T4 76
+SSSF_PIN_DECL(T4, GPIOJ4, VGAHS, FUNC_DESC_SET(SCU84, 12));
+
+#define U2 77
+SSSF_PIN_DECL(U2, GPIOJ5, VGAVS, FUNC_DESC_SET(SCU84, 13));
+
+#define T2 78
+SSSF_PIN_DECL(T2, GPIOJ6, DDCCLK, FUNC_DESC_SET(SCU84, 14));
+
+#define T1 79
+SSSF_PIN_DECL(T1, GPIOJ7, DDCDAT, FUNC_DESC_SET(SCU84, 15));
+
+FUNC_EXPR_DECL_SINGLE(I2C5, FUNC_DESC_SET(SCU90, 18));
+
+#define E3 80
+SS_PIN_DECL(E3, GPIOK0, I2C5);
+
+#define D2 81
+SS_PIN_DECL(D2, GPIOK1, I2C5);
+
+FUNC_GROUP_DECL(I2C5, E3, D2);
+
+FUNC_EXPR_DECL_SINGLE(I2C6, FUNC_DESC_SET(SCU90, 19));
+
+#define C1 82
+SS_PIN_DECL(C1, GPIOK2, I2C6);
+
+#define F4 83
+SS_PIN_DECL(F4, GPIOK3, I2C6);
+
+FUNC_GROUP_DECL(I2C6, C1, F4);
+
+FUNC_EXPR_DECL_SINGLE(I2C7, FUNC_DESC_SET(SCU90, 20));
+
+#define E2 84
+SS_PIN_DECL(E2, GPIOK4, I2C7);
+
+#define D1 85
+SS_PIN_DECL(D1, GPIOK5, I2C7);
+
+FUNC_GROUP_DECL(I2C7, E2, D1);
+
+FUNC_EXPR_DECL_SINGLE(I2C8, FUNC_DESC_SET(SCU90, 21));
+
+#define G5 86
+SS_PIN_DECL(G5, GPIOK6, I2C8);
+
+#define F3 87
+SS_PIN_DECL(F3, GPIOK7, I2C8);
+
+FUNC_GROUP_DECL(I2C8, G5, F3);
+
+#define U1 88
+SSSF_PIN_DECL(U1, GPIOL0, NCTS1, FUNC_DESC_SET(SCU84, 16));
+
+#define VPI18_DESC { SCU84, GENMASK(5, 4), 1, 0 }
+#define VPI24_DESC { SCU84, GENMASK(5, 4), 2, 0 }
+#define VPI30_DESC { SCU84, GENMASK(5, 4), 3, 0 }
+
+#define VPIEN_0_DESC \
+	{ SCU84, GENMASK(21, 17), GENMASK(4, 0), 0 }
+#define VPIEN_1_DESC \
+	{ SCU84, GENMASK(23, 22), GENMASK(1, 0), 0 }
+#define VPIEN_2_DESC \
+	{ SCU88, GENMASK(1, 0), GENMASK(1, 0), 0 }
+#define VPIEN_3_DESC \
+	{ SCU88, GENMASK(5, 2), GENMASK(3, 0), 0 }
+#define VPIEN_4_DESC \
+	{ SCU88, GENMASK(7, 6), GENMASK(1, 0), 0 }
+
+FUNC_EXPR_DECL(VPI18,
+		VPI18_DESC,
+		VPIEN_0_DESC,
+		VPIEN_3_DESC);
+
+FUNC_EXPR_DECL(VPI24,
+		VPI24_DESC,
+		VPIEN_0_DESC,
+		VPIEN_3_DESC,
+		VPIEN_4_DESC);
+
+FUNC_EXPR_DECL(VPI30,
+		VPI30_DESC,
+		VPIEN_0_DESC,
+		VPIEN_1_DESC,
+		VPIEN_2_DESC,
+		VPIEN_3_DESC);
+
+FUNC_EXPR_LIST_DECL(VPI,
+		FUNC_EXPR_PTR(VPI18),
+		FUNC_EXPR_PTR(VPI24),
+		FUNC_EXPR_PTR(VPI30),
+		NULL);
+
+#define T5 89
+FUNC_EXPR_DECL_SINGLE(NDCD1, FUNC_DESC_SET(SCU84, 17));
+MS_PIN_DECL(T5, GPIOL1, VPI, NDCD1);
+FUNC_GROUP_DECL(NDCD1, T5);
+
+#define U3 90
+FUNC_EXPR_DECL_SINGLE(NDSR1, FUNC_DESC_SET(SCU84, 18));
+MS_PIN_DECL(U3, GPIOL2, VPI, NDSR1);
+FUNC_GROUP_DECL(NDSR1, U3);
+
+#define V1 91
+FUNC_EXPR_DECL_SINGLE(NRI1, FUNC_DESC_SET(SCU84, 19));
+MS_PIN_DECL(V1, GPIOL3, VPI, NRI1);
+FUNC_GROUP_DECL(NRI1, V1);
+
+#define U4 92
+FUNC_EXPR_DECL_SINGLE(NDTR1, FUNC_DESC_SET(SCU84, 20));
+MS_PIN_DECL(U4, GPIOL4, VPI, NDTR1);
+FUNC_GROUP_DECL(NDTR1, U4);
+
+#define V2 93
+FUNC_EXPR_DECL_SINGLE(NRTS1, FUNC_DESC_SET(SCU84, 21));
+MS_PIN_DECL(V2, GPIOL5, VPI, NRTS1);
+FUNC_GROUP_DECL(NRTS1, V2);
+
+#define W1 94
+FUNC_EXPR_DECL_SINGLE(TXD1, FUNC_DESC_SET(SCU84, 22));
+MS_PIN_DECL(W1, GPIOL6, VPI, TXD1);
+FUNC_GROUP_DECL(TXD1, W1);
+
+#define U5 95
+FUNC_EXPR_DECL_SINGLE(RXD1, FUNC_DESC_SET(SCU84, 23));
+MS_PIN_DECL(U5, GPIOL7, VPI, RXD1);
+FUNC_GROUP_DECL(RXD1, U5);
+
+#define W4 104
+FUNC_EXPR_DECL_SINGLE(PWM0, FUNC_DESC_SET(SCU88, 0));
+MS_PIN_DECL(W4, GPION0, VPI, PWM0);
+FUNC_GROUP_DECL(PWM0, W4);
+
+#define Y3 105
+FUNC_EXPR_DECL_SINGLE(PWM1, FUNC_DESC_SET(SCU88, 1));
+MS_PIN_DECL(Y3, GPION1, VPI, PWM1);
+FUNC_GROUP_DECL(PWM1, Y3);
+
+#define AA2 106
+FUNC_EXPR_DECL_SINGLE(PWM2, FUNC_DESC_SET(SCU88, 2));
+MS_PIN_DECL(AA2, GPION2, VPI, PWM2);
+FUNC_GROUP_DECL(PWM2, AA2);
+
+#define AB1 107
+FUNC_EXPR_DECL_SINGLE(PWM3, FUNC_DESC_SET(SCU88, 3));
+MS_PIN_DECL(AB1, GPION3, VPI, PWM3);
+FUNC_GROUP_DECL(PWM3, AB1);
+
+#define W5 108
+FUNC_EXPR_DECL_SINGLE(PWM4, FUNC_DESC_SET(SCU88, 4));
+MS_PIN_DECL(W5, GPION4, VPI, PWM4);
+FUNC_GROUP_DECL(PWM4, W5);
+
+#define Y4 109
+FUNC_EXPR_DECL_SINGLE(PWM5, FUNC_DESC_SET(SCU88, 5));
+MS_PIN_DECL(Y4, GPION5, VPI, PWM5);
+FUNC_GROUP_DECL(PWM5, Y4);
+
+#define AA3 110
+FUNC_EXPR_DECL_SINGLE(PWM6, FUNC_DESC_SET(SCU88, 6));
+MS_PIN_DECL(AA3, GPION6, VPI, PWM6);
+FUNC_GROUP_DECL(PWM6, AA3);
+
+#define AB2 111
+FUNC_EXPR_DECL_SINGLE(PWM7, FUNC_DESC_SET(SCU88, 7));
+MS_PIN_DECL(AB2, GPION7, VPI, PWM7);
+FUNC_GROUP_DECL(PWM7, AB2);
+
+FUNC_GROUP_DECL(VPI18, T5, U3, V1, U4, V2, AA22, W5, Y4, AA3, AB2);
+FUNC_GROUP_DECL(VPI24, T5, U3, V1, U4, V2, AA22, W5, Y4, AA3, AB2);
+FUNC_GROUP_DECL(VPI30, T5, U3, V1, U4, V2, W1, U5, W4, Y3, AA22, W5, Y4, AA3,
+		AB2);
+
+#define AA7 126
+SSSF_PIN_DECL(AA7, GPIOP6, BMCINT, FUNC_DESC_SET(SCU88, 22));
+
+#define AB7 127
+SSSF_PIN_DECL(AB7, GPIOP7, FLACK, FUNC_DESC_SET(SCU88, 23));
+
+FUNC_EXPR_DECL(I2C3, FUNC_DESC_SET(SCU90, 16));
+FUNC_EXPR_LIST_DECL_SINGLE(I2C3);
+
+#define D3 128
+SS_PIN_DECL(D3, GPIOQ0, I2C3);
+
+#define C2 129
+SS_PIN_DECL(C2, GPIOQ1, I2C3);
+
+FUNC_GROUP_DECL(I2C3, D3, C2);
+
+FUNC_EXPR_DECL_SINGLE(I2C4, FUNC_DESC_SET(SCU90, 17));
+
+#define B1 130
+SS_PIN_DECL(B1, GPIOQ2, I2C4);
+
+#define F5 131
+SS_PIN_DECL(F5, GPIOQ3, I2C4);
+
+FUNC_GROUP_DECL(I2C4, B1, F5);
+
+#define VPOOFF1_DESC { SCU94, GENMASK(1, 0), 3, 0 }
+#define VPO12_DESC { SCU94, GENMASK(1, 0), 1, 0 }
+#define VPO24_DESC { SCU94, GENMASK(1, 0), 2, 0 }
+
+/* Enables an incomplete list of signals, only enough to cover the pins that we
+ * need to describe at the moment
+ */
+#define VPOEN_0_DESC \
+	{ SCU88, GENMASK(29, 28), GENMASK(1, 0), 0 }
+#define VPOEN_1_DESC \
+	{ SCU8C, GENMASK(3, 0), GENMASK(3, 0), 0 }
+#define VPOEN_2_DESC \
+	{ SCU8C, GENMASK(7, 6), GENMASK(1, 0), 0 }
+
+FUNC_EXPR_LIST_DECL(ROM,
+		FUNC_EXPR_PTR(ROM8),
+		FUNC_EXPR_PTR(ROM16),
+		FUNC_EXPR_PTR(ROM16S),
+		NULL);
+
+#define V20 136
+MS_PIN_DECL_(V20, GPIOR0, FUNC_EXPR_LIST_PTR(ROM), NULL);
+
+FUNC_EXPR_DECL(VPO12,
+		VPO12_DESC,
+		VPOEN_0_DESC,
+		VPOEN_1_DESC,
+		VPOEN_2_DESC);
+
+FUNC_EXPR_DECL(VPO24,
+		VPO24_DESC,
+		VPOEN_0_DESC,
+		VPOEN_1_DESC,
+		VPOEN_2_DESC);
+
+FUNC_EXPR_DECL(VPOOFF1,
+		VPOOFF1_DESC,
+		VPOEN_0_DESC,
+		VPOEN_1_DESC,
+		VPOEN_2_DESC);
+
+FUNC_EXPR_LIST_DECL(VPO,
+		FUNC_EXPR_PTR(VPO12),
+		FUNC_EXPR_PTR(VPO24),
+		FUNC_EXPR_PTR(VPOOFF1),
+		NULL);
+
+#define U21 144
+MS_PIN_DECL(U21, GPIOS0, ROM, VPO);
+
+#define T19 145
+MS_PIN_DECL(T19, GPIOS1, ROM, VPO);
+
+#define V22 146
+MS_PIN_DECL(V22, GPIOS2, ROM, VPO);
+
+#define U20 147
+MS_PIN_DECL(U20, GPIOS3, ROM, VPO);
+
+#define R18 148
+MS_PIN_DECL_(R18, GPIOS4, FUNC_EXPR_LIST_PTR(ROM), NULL);
+
+#define N21 149
+MS_PIN_DECL_(N21, GPIOS5, FUNC_EXPR_LIST_PTR(ROM), NULL);
+
+#define L22 150
+MS_PIN_DECL(L22, GPIOS6, ROM, VPO);
+
+#define K18 151
+MS_PIN_DECL(K18, GPIOS7, ROM, VPO);
+
+FUNC_GROUP_DECL(ROM8, V20, U21, T19, V22, U20, R18, N21, L22, K18);
+FUNC_GROUP_DECL(ROM16, V20, U21, T19, V22, U20, R18, N21, L22, K18,
+		A8, C7, B7, A7, D7, B6, A6, E7);
+FUNC_GROUP_DECL(VPO12, U21, T19, V22, U20);
+FUNC_GROUP_DECL(VPO24, U21, T19, V22, U20, L22, K18);
+
+#define AST_PINCTRL_PIN(name_) \
+	[name_] = { \
+		.number = name_, \
+		.name = #name_, \
+		.drv_data = (void *) &(PIN_SYM(name_)) \
+	}
+
+/* Note we account for GPIOY4-GPIOY7 even though they're not valid, thus 216
+ * pins becomes 220.
+ */
+#define AST2400_NR_GPIOS 220
+
+static struct pinctrl_pin_desc ast2400_pins[AST2400_NR_GPIOS] = {
+	AST_PINCTRL_PIN(A4),
+	AST_PINCTRL_PIN(C4),
+	AST_PINCTRL_PIN(B3),
+	AST_PINCTRL_PIN(A2),
+	AST_PINCTRL_PIN(E5),
+	AST_PINCTRL_PIN(D4),
+	AST_PINCTRL_PIN(C3),
+	AST_PINCTRL_PIN(B2),
+	AST_PINCTRL_PIN(A1),
+	AST_PINCTRL_PIN(D18),
+	AST_PINCTRL_PIN(B19),
+	AST_PINCTRL_PIN(D17),
+	AST_PINCTRL_PIN(E16),
+	AST_PINCTRL_PIN(C17),
+	AST_PINCTRL_PIN(AA22),
+	AST_PINCTRL_PIN(U18),
+	AST_PINCTRL_PIN(A8),
+	AST_PINCTRL_PIN(C7),
+	AST_PINCTRL_PIN(B7),
+	AST_PINCTRL_PIN(A7),
+	AST_PINCTRL_PIN(D7),
+	AST_PINCTRL_PIN(B6),
+	AST_PINCTRL_PIN(A6),
+	AST_PINCTRL_PIN(E7),
+	AST_PINCTRL_PIN(T4),
+	AST_PINCTRL_PIN(U2),
+	AST_PINCTRL_PIN(T2),
+	AST_PINCTRL_PIN(T1),
+	AST_PINCTRL_PIN(E3),
+	AST_PINCTRL_PIN(D2),
+	AST_PINCTRL_PIN(C1),
+	AST_PINCTRL_PIN(F4),
+	AST_PINCTRL_PIN(E2),
+	AST_PINCTRL_PIN(D1),
+	AST_PINCTRL_PIN(G5),
+	AST_PINCTRL_PIN(F3),
+	AST_PINCTRL_PIN(U1),
+	AST_PINCTRL_PIN(T5),
+	AST_PINCTRL_PIN(U3),
+	AST_PINCTRL_PIN(V1),
+	AST_PINCTRL_PIN(U4),
+	AST_PINCTRL_PIN(V2),
+	AST_PINCTRL_PIN(W1),
+	AST_PINCTRL_PIN(U5),
+	AST_PINCTRL_PIN(W4),
+	AST_PINCTRL_PIN(Y3),
+	AST_PINCTRL_PIN(AA2),
+	AST_PINCTRL_PIN(AB1),
+	AST_PINCTRL_PIN(W5),
+	AST_PINCTRL_PIN(Y4),
+	AST_PINCTRL_PIN(AA3),
+	AST_PINCTRL_PIN(AB2),
+	AST_PINCTRL_PIN(AA7),
+	AST_PINCTRL_PIN(AB7),
+	AST_PINCTRL_PIN(D3),
+	AST_PINCTRL_PIN(C2),
+	AST_PINCTRL_PIN(B1),
+	AST_PINCTRL_PIN(F5),
+	AST_PINCTRL_PIN(V20),
+	AST_PINCTRL_PIN(U21),
+	AST_PINCTRL_PIN(T19),
+	AST_PINCTRL_PIN(V22),
+	AST_PINCTRL_PIN(U20),
+	AST_PINCTRL_PIN(R18),
+	AST_PINCTRL_PIN(N21),
+	AST_PINCTRL_PIN(L22),
+	AST_PINCTRL_PIN(K18),
+};
+
+struct ast2400_pin_group {
+	const char *name;
+	const unsigned int *pins;
+	const unsigned npins;
+};
+
+#define AST_PINCTRL_GROUP(name_) { \
+	.name = #name_, \
+	.pins = &(PIN_GROUP_SYM(name_))[0], \
+	.npins = ARRAY_SIZE(PIN_GROUP_SYM(name_)), \
+}
+
+static const struct ast2400_pin_group ast2400_groups[] = {
+	AST_PINCTRL_GROUP(TIMER3),
+	AST_PINCTRL_GROUP(SD1),
+	AST_PINCTRL_GROUP(I2C10),
+	AST_PINCTRL_GROUP(I2C11),
+	AST_PINCTRL_GROUP(I2C12),
+	AST_PINCTRL_GROUP(I2C13),
+	AST_PINCTRL_GROUP(NCTS4),
+	AST_PINCTRL_GROUP(ACPI),
+	AST_PINCTRL_GROUP(NDCD4),
+	AST_PINCTRL_GROUP(SIOPBI),
+	AST_PINCTRL_GROUP(NRI4),
+	AST_PINCTRL_GROUP(SIOPBO),
+	AST_PINCTRL_GROUP(TXD4),
+	AST_PINCTRL_GROUP(RXD4),
+	AST_PINCTRL_GROUP(FLBUSY),
+	AST_PINCTRL_GROUP(FLWP),
+	AST_PINCTRL_GROUP(UART6),
+	AST_PINCTRL_GROUP(VGAHS),
+	AST_PINCTRL_GROUP(VGAVS),
+	AST_PINCTRL_GROUP(DDCCLK),
+	AST_PINCTRL_GROUP(DDCDAT),
+	AST_PINCTRL_GROUP(I2C5),
+	AST_PINCTRL_GROUP(I2C6),
+	AST_PINCTRL_GROUP(I2C7),
+	AST_PINCTRL_GROUP(I2C8),
+	AST_PINCTRL_GROUP(NCTS1),
+	AST_PINCTRL_GROUP(NDCD1),
+	AST_PINCTRL_GROUP(NDSR1),
+	AST_PINCTRL_GROUP(NRI1),
+	AST_PINCTRL_GROUP(NDTR1),
+	AST_PINCTRL_GROUP(NRTS1),
+	AST_PINCTRL_GROUP(TXD1),
+	AST_PINCTRL_GROUP(RXD1),
+	AST_PINCTRL_GROUP(PWM0),
+	AST_PINCTRL_GROUP(PWM1),
+	AST_PINCTRL_GROUP(PWM2),
+	AST_PINCTRL_GROUP(PWM3),
+	AST_PINCTRL_GROUP(PWM4),
+	AST_PINCTRL_GROUP(PWM5),
+	AST_PINCTRL_GROUP(PWM6),
+	AST_PINCTRL_GROUP(PWM7),
+	AST_PINCTRL_GROUP(VPI18),
+	AST_PINCTRL_GROUP(VPI24),
+	AST_PINCTRL_GROUP(VPI30),
+	AST_PINCTRL_GROUP(BMCINT),
+	AST_PINCTRL_GROUP(FLACK),
+	AST_PINCTRL_GROUP(I2C3),
+	AST_PINCTRL_GROUP(I2C4),
+	AST_PINCTRL_GROUP(ROM8),
+	AST_PINCTRL_GROUP(ROM16),
+	AST_PINCTRL_GROUP(VPO12),
+	AST_PINCTRL_GROUP(VPO24),
+};
+
+struct ast2400_pin_function {
+	const char *name;
+	const char *const *groups;
+	unsigned ngroups;
+	const struct func_expr *expr;
+};
+
+#define AST_PINCTRL_FUNC(name_, ...) { \
+	.name = #name_, \
+	.groups = &FUNC_GROUP_SYM(name_)[0], \
+	.ngroups = ARRAY_SIZE(FUNC_GROUP_SYM(name_)), \
+	.expr = FUNC_EXPR_PTR(name_), \
+}
+
+static const struct ast2400_pin_function ast2400_functions[] = {
+	AST_PINCTRL_FUNC(TIMER3),
+	AST_PINCTRL_FUNC(SD1),
+	AST_PINCTRL_FUNC(I2C10),
+	AST_PINCTRL_FUNC(I2C11),
+	AST_PINCTRL_FUNC(I2C12),
+	AST_PINCTRL_FUNC(I2C13),
+	AST_PINCTRL_FUNC(NCTS4),
+	AST_PINCTRL_FUNC(ACPI),
+	AST_PINCTRL_FUNC(NDCD4),
+	AST_PINCTRL_FUNC(SIOPBI),
+	AST_PINCTRL_FUNC(NRI4),
+	AST_PINCTRL_FUNC(SIOPBO),
+	AST_PINCTRL_FUNC(TXD4),
+	AST_PINCTRL_FUNC(RXD4),
+	AST_PINCTRL_FUNC(FLBUSY),
+	AST_PINCTRL_FUNC(FLWP),
+	AST_PINCTRL_FUNC(UART6),
+	AST_PINCTRL_FUNC(VGAHS),
+	AST_PINCTRL_FUNC(VGAVS),
+	AST_PINCTRL_FUNC(DDCCLK),
+	AST_PINCTRL_FUNC(DDCDAT),
+	AST_PINCTRL_FUNC(I2C5),
+	AST_PINCTRL_FUNC(I2C6),
+	AST_PINCTRL_FUNC(I2C7),
+	AST_PINCTRL_FUNC(I2C8),
+	AST_PINCTRL_FUNC(NCTS1),
+	AST_PINCTRL_FUNC(NDCD1),
+	AST_PINCTRL_FUNC(NDSR1),
+	AST_PINCTRL_FUNC(NRI1),
+	AST_PINCTRL_FUNC(NDTR1),
+	AST_PINCTRL_FUNC(NRTS1),
+	AST_PINCTRL_FUNC(TXD1),
+	AST_PINCTRL_FUNC(RXD1),
+	AST_PINCTRL_FUNC(PWM0),
+	AST_PINCTRL_FUNC(PWM1),
+	AST_PINCTRL_FUNC(PWM2),
+	AST_PINCTRL_FUNC(PWM3),
+	AST_PINCTRL_FUNC(PWM4),
+	AST_PINCTRL_FUNC(PWM5),
+	AST_PINCTRL_FUNC(PWM6),
+	AST_PINCTRL_FUNC(PWM7),
+	AST_PINCTRL_FUNC(VPI18),
+	AST_PINCTRL_FUNC(VPI24),
+	AST_PINCTRL_FUNC(VPI30),
+	AST_PINCTRL_FUNC(BMCINT),
+	AST_PINCTRL_FUNC(FLACK),
+	AST_PINCTRL_FUNC(I2C3),
+	AST_PINCTRL_FUNC(I2C4),
+	AST_PINCTRL_FUNC(ROM8),
+	AST_PINCTRL_FUNC(ROM16),
+	AST_PINCTRL_FUNC(VPO12),
+	AST_PINCTRL_FUNC(VPO24),
+};
+
+struct ast2400_pinctrl_data {
+	void __iomem *reg_base;
+
+	const struct pinctrl_pin_desc *pins;
+	const unsigned npins;
+
+	const struct ast2400_pin_group *groups;
+	const unsigned ngroups;
+
+	const struct ast2400_pin_function *functions;
+	const unsigned nfunctions;
+};
+
+static struct ast2400_pinctrl_data ast2400_pinctrl = {
+	.pins = ast2400_pins,
+	.npins = ARRAY_SIZE(ast2400_pins),
+	.groups = ast2400_groups,
+	.ngroups = ARRAY_SIZE(ast2400_groups),
+	.functions = ast2400_functions,
+	.nfunctions = ARRAY_SIZE(ast2400_functions),
+};
+
+static int ast2400_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+	return pdata->ngroups;
+}
+
+static const char *ast2400_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+		unsigned group)
+{
+	struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+	return pdata->groups[group].name;
+}
+
+static int ast2400_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+		unsigned group, const unsigned **pins, unsigned *npins)
+{
+	struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = &pdata->groups[group].pins[0];
+	*npins = pdata->groups[group].npins;
+
+	return 0;
+}
+
+static void ast2400_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+		struct seq_file *s, unsigned offset)
+{
+	seq_printf(s, " %s", dev_name(pctldev->dev));
+}
+
+static struct pinctrl_ops ast2400_pinctrl_ops = {
+	.get_groups_count = ast2400_pinctrl_get_groups_count,
+	.get_group_name = ast2400_pinctrl_get_group_name,
+	.get_group_pins = ast2400_pinctrl_get_group_pins,
+	.pin_dbg_show = ast2400_pinctrl_pin_dbg_show,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+	.dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int ast2400_pinmux_get_fn_count(struct pinctrl_dev *pctldev)
+{
+	struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+	return pdata->nfunctions;
+}
+
+static const char *ast2400_pinmux_get_fn_name(struct pinctrl_dev *pctldev,
+						unsigned function)
+{
+	struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+	return pdata->functions[function].name;
+}
+
+static int ast2400_pinmux_get_fn_groups(struct pinctrl_dev *pctldev,
+		unsigned function, const char * const **groups,
+		unsigned * const num_groups)
+{
+	struct ast2400_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pdata->functions[function].groups;
+	*num_groups = pdata->functions[function].ngroups;
+
+	return 0;
+}
+
+static bool func_desc_eval(const struct func_desc *desc, void __iomem *base)
+{
+	u32 raw = ioread32(base + desc->reg);
+
+	return ((raw & desc->mask) >> __ffs(desc->mask)) == desc->enable;
+}
+
+static bool func_expr_eval(const struct func_expr *expr, void __iomem *base)
+{
+	bool ret = true;
+	int i;
+
+	for (i = 0; i < expr->ndescs; i++) {
+		const struct func_desc *desc = &expr->descs[i];
+
+		ret = ret && func_desc_eval(desc, base);
+	}
+
+	return ret;
+}
+
+static bool func_expr_enable(const struct func_expr *expr, void __iomem *base)
+{
+	int i;
+	int ret;
+
+	ret = func_expr_eval(expr, base);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < expr->ndescs; i++) {
+		const struct func_desc *desc = &expr->descs[i];
+		u32 val;
+
+		if (desc->reg == STRAP)
+			continue;
+
+		val = ioread32(base + desc->reg);
+		val &= ~desc->mask;
+		val |= desc->enable << __ffs(desc->mask);
+		iowrite32(val, base + desc->reg);
+	}
+
+	ret = func_expr_eval(expr, base);
+	return ret;
+}
+
+static bool func_expr_disable(const struct func_expr *expr, void __iomem *base)
+{
+	int i;
+	bool ret;
+
+	/* Ensure that we change any unsupported state to disabled */
+	for (i = 0; i < expr->ndescs; i++) {
+		const struct func_desc *desc = &expr->descs[i];
+		u32 val;
+
+		if (desc->reg == STRAP)
+			continue;
+
+		val = ioread32(base + desc->reg);
+		val &= ~desc->mask;
+		val |= (desc->disable << __ffs(desc->mask));
+		iowrite32(val, base + desc->reg);
+	}
+
+	ret = !func_expr_eval(expr, base);
+	return ret;
+}
+
+static inline bool maybe_disable(const struct func_expr **expr,
+		void __iomem *base)
+{
+	bool ret;
+
+	if (!expr)
+		return true;
+
+	while (*expr) {
+		ret |= func_expr_disable(*expr, base);
+		expr++;
+	}
+	return ret;
+}
+
+static bool sig_in_exprs(const struct func_expr **exprs,
+		const struct func_expr *sig)
+{
+	if (!exprs)
+		return false;
+
+	while (*exprs) {
+		if (sig == *exprs)
+			return true;
+		exprs++;
+	}
+	return false;
+}
+
+static int ast2400_pinmux_set_mux(struct pinctrl_dev *pctldev,
+		unsigned function, unsigned group)
+{
+	int i;
+	const struct ast2400_pinctrl_data *pdata =
+		pinctrl_dev_get_drvdata(pctldev);
+	const struct ast2400_pin_group *pgroup = &pdata->groups[group];
+	const struct ast2400_pin_function *pfunc =
+		&pdata->functions[function];
+
+	for (i = 0; i < pgroup->npins; i++) {
+		int pin = pgroup->pins[i];
+		const struct pin_prio *pprio = pdata->pins[pin].drv_data;
+		const struct func_expr *func = pfunc->expr;
+
+		if (!pprio)
+			return -1;
+
+		/* If low priority is requested, ensure high is disabled */
+		if (sig_in_exprs(pprio->low, func)) {
+			if (!maybe_disable(pprio->high, pdata->reg_base)) {
+				pr_err("Failed to disable high priority function on pin %d\n",
+						pin);
+				return -1;
+			}
+		}
+
+		/* Nothing to do if we're already enabled */
+		if (func_expr_eval(func, pdata->reg_base))
+			continue;
+
+		/* Configure the pin */
+		if (!func_expr_enable(func, pdata->reg_base))
+			return -1;
+	}
+
+	return 0;
+}
+
+static int ast2400_gpio_request_enable(struct pinctrl_dev *pctldev,
+		struct pinctrl_gpio_range *range,
+		unsigned offset)
+{
+	unsigned pin = range->base + offset;
+	const struct ast2400_pinctrl_data *pdata =
+		pinctrl_dev_get_drvdata(pctldev);
+	const struct pin_prio *pprio =
+		pdata->pins[pin].drv_data;
+
+	if (!pprio)
+		return 0;
+
+	if (!maybe_disable(pprio->high, pdata->reg_base))
+		return -1;
+
+	if (!maybe_disable(pprio->low, pdata->reg_base))
+		return -1;
+
+	return 0;
+}
+
+static struct pinmux_ops ast2400_pinmux_ops = {
+	.get_functions_count = ast2400_pinmux_get_fn_count,
+	.get_function_name = ast2400_pinmux_get_fn_name,
+	.get_function_groups = ast2400_pinmux_get_fn_groups,
+	.set_mux = ast2400_pinmux_set_mux,
+	.gpio_request_enable = ast2400_gpio_request_enable,
+	.strict = true,
+};
+
+static int ast2400_pin_config_get(struct pinctrl_dev *pctldev,
+		unsigned pin,
+		unsigned long *config)
+{
+	return 0;
+}
+
+static int ast2400_pin_config_set(struct pinctrl_dev *pctldev,
+		unsigned pin,
+		unsigned long *configs,
+		unsigned num_configs)
+{
+	return 0;
+}
+
+static struct pinconf_ops ast2400_pinconf_ops = {
+	.pin_config_get = ast2400_pin_config_get,
+	.pin_config_set = ast2400_pin_config_set,
+};
+
+static struct pinctrl_desc ast2400_pinctrl_desc = {
+	.name = "pinctrl-ast2400",
+	.pins = ast2400_pins,
+	.npins = ARRAY_SIZE(ast2400_pins),
+	.pctlops = &ast2400_pinctrl_ops,
+	.pmxops = &ast2400_pinmux_ops,
+	.confops = &ast2400_pinconf_ops,
+	.owner = THIS_MODULE,
+};
+
+static struct pinctrl_gpio_range ast2400_gpios = {
+	.name = "ast2400-pctrl-gpio-range",
+	.npins = ARRAY_SIZE(ast2400_pins),
+};
+
+static int __init ast2400_pinctrl_probe(struct platform_device *pdev)
+{
+	struct ast2400_pinctrl_data *pdata = &ast2400_pinctrl;
+	struct resource *res;
+	struct pinctrl_dev *pctl;
+	int i;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pdata->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pdata->reg_base))
+		return PTR_ERR(pdata->reg_base);
+
+	/* We allocated space for all pins, make sure we initialise all pin
+	 * numbers. Those pins we haven't defined won't yet have had their
+	 * number initialised, and it's effectively a no-op for those which
+	 * have.
+	 */
+	for (i = 0; i < ARRAY_SIZE(ast2400_pins); i++)
+		ast2400_pins[i].number = i;
+
+	pctl = pinctrl_register(&ast2400_pinctrl_desc, &pdev->dev, pdata);
+
+	if (IS_ERR(pctl)) {
+		dev_err(&pdev->dev, "Failed to register pinctrl\n");
+		return PTR_ERR(pctl);
+	}
+
+	platform_set_drvdata(pdev, pdata);
+
+	/* grange.name = "exynos5440-pctrl-gpio-range"; */
+	pinctrl_add_gpio_range(pctl, &ast2400_gpios);
+
+	return 0;
+}
+
+static const struct of_device_id ast2400_pinctrl_of_match[] = {
+	{ .compatible = "aspeed,ast2400-pinctrl", },
+	{ },
+};
+
+static struct platform_driver ast2400_pinctrl_driver = {
+	.driver = {
+		.name = "pinctrl-ast2400",
+		.of_match_table = ast2400_pinctrl_of_match,
+	},
+};
+
+module_platform_driver_probe(ast2400_pinctrl_driver, ast2400_pinctrl_probe);
+
+MODULE_AUTHOR("Andrew Jeffery <andrew@xxxxxxxx>");
+MODULE_DESCRIPTION("ASPEED AST2400 pinctrl driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux