Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60ad481f authored by Linus Walleij's avatar Linus Walleij
Browse files

pinctrl: gemini: Implement clock skew/delay config



This enabled pin config on the Gemini driver and implements
pin skew/delay so that the ethernet pins clocking can be
properly configured.

Acked-by: default avatarHans Ulli Kroll <ulli.kroll@googlemail.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 1c5b7f3c
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -9,8 +9,14 @@ The pin controller node must be a subnode of the system controller node.
Required properties:
- compatible: "cortina,gemini-pinctrl"

Subnodes of the pin controller contain pin control multiplexing set-up.
Please refer to pinctrl-bindings.txt for generic pin multiplexing nodes.
Subnodes of the pin controller contain pin control multiplexing set-up
and pin configuration of individual pins.

Please refer to pinctrl-bindings.txt for generic pin multiplexing nodes
and generic pin config nodes.

Supported configurations:
- skew-delay is supported on the Ethernet pins

Example:

+174 −4
Original line number Diff line number Diff line
@@ -24,6 +24,19 @@
#define DRIVER_NAME "pinctrl-gemini"

/**
 * struct gemini_pin_conf - information about configuring a pin
 * @pin: the pin number
 * @reg: config register
 * @mask: the bits affecting the configuration of the pin
 */
struct gemini_pin_conf {
	unsigned int pin;
	u32 reg;
	u32 mask;
};

/**
 * struct gemini_pmx - state holder for the gemini pin controller
 * @dev: a pointer back to containing device
 * @virtbase: the offset to the controller in virtual memory
 * @map: regmap to access registers
@@ -31,6 +44,8 @@
 * @is_3516: whether the SoC/package is the 3516 variant
 * @flash_pin: whether the flash pin (extended pins for parallel
 * flash) is set
 * @confs: pin config information
 * @nconfs: number of pin config information items
 */
struct gemini_pmx {
	struct device *dev;
@@ -39,6 +54,8 @@ struct gemini_pmx {
	bool is_3512;
	bool is_3516;
	bool flash_pin;
	const struct gemini_pin_conf *confs;
	unsigned int nconfs;
};

/**
@@ -59,6 +76,13 @@ struct gemini_pin_group {
	u32 value;
};

/* Some straight-forward control registers */
#define GLOBAL_WORD_ID		0x00
#define GLOBAL_STATUS		0x04
#define GLOBAL_STATUS_FLPIN	BIT(20)
#define GLOBAL_GMAC_CTRL_SKEW	0x1c
#define GLOBAL_GMAC0_DATA_SKEW	0x20
#define GLOBAL_GMAC1_DATA_SKEW	0x24
/*
 * Global Miscellaneous Control Register
 * This register controls all Gemini pad/pin multiplexing
@@ -71,9 +95,6 @@ struct gemini_pin_group {
 *   DISABLED again. So you select a flash configuration once, and then
 *   you are stuck with it.
 */
#define GLOBAL_WORD_ID		0x00
#define GLOBAL_STATUS		0x04
#define GLOBAL_STATUS_FLPIN	BIT(20)
#define GLOBAL_MISC_CTRL	0x30
#define TVC_CLK_PAD_ENABLE	BIT(20)
#define PCI_CLK_PAD_ENABLE	BIT(17)
@@ -1925,7 +1946,7 @@ static const struct pinctrl_ops gemini_pctrl_ops = {
	.get_group_name = gemini_get_group_name,
	.get_group_pins = gemini_get_group_pins,
	.pin_dbg_show = gemini_pin_dbg_show,
	.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
	.dt_free_map = pinconf_generic_dt_free_map,
};

@@ -2203,10 +2224,155 @@ static const struct pinmux_ops gemini_pmx_ops = {
	.set_mux = gemini_pmx_set_mux,
};

#define GEMINI_CFGPIN(_n, _r, _lb, _hb) {	\
	.pin = _n,				\
	.reg = _r,				\
	.mask = GENMASK(_hb, _lb)		\
}

static const struct gemini_pin_conf gemini_confs_3512[] = {
	GEMINI_CFGPIN(259, GLOBAL_GMAC_CTRL_SKEW, 0, 3), /* GMAC0 RXDV */
	GEMINI_CFGPIN(277, GLOBAL_GMAC_CTRL_SKEW, 4, 7), /* GMAC0 RXC */
	GEMINI_CFGPIN(241, GLOBAL_GMAC_CTRL_SKEW, 8, 11), /* GMAC0 TXEN */
	GEMINI_CFGPIN(312, GLOBAL_GMAC_CTRL_SKEW, 12, 15), /* GMAC0 TXC */
	GEMINI_CFGPIN(298, GLOBAL_GMAC_CTRL_SKEW, 16, 19), /* GMAC1 RXDV */
	GEMINI_CFGPIN(280, GLOBAL_GMAC_CTRL_SKEW, 20, 23), /* GMAC1 RXC */
	GEMINI_CFGPIN(316, GLOBAL_GMAC_CTRL_SKEW, 24, 27), /* GMAC1 TXEN */
	GEMINI_CFGPIN(243, GLOBAL_GMAC_CTRL_SKEW, 28, 31), /* GMAC1 TXC */
	GEMINI_CFGPIN(295, GLOBAL_GMAC0_DATA_SKEW, 0, 3), /* GMAC0 RXD0 */
	GEMINI_CFGPIN(313, GLOBAL_GMAC0_DATA_SKEW, 4, 7), /* GMAC0 RXD1 */
	GEMINI_CFGPIN(242, GLOBAL_GMAC0_DATA_SKEW, 8, 11), /* GMAC0 RXD2 */
	GEMINI_CFGPIN(260, GLOBAL_GMAC0_DATA_SKEW, 12, 15), /* GMAC0 RXD3 */
	GEMINI_CFGPIN(294, GLOBAL_GMAC0_DATA_SKEW, 16, 19), /* GMAC0 TXD0 */
	GEMINI_CFGPIN(276, GLOBAL_GMAC0_DATA_SKEW, 20, 23), /* GMAC0 TXD1 */
	GEMINI_CFGPIN(258, GLOBAL_GMAC0_DATA_SKEW, 24, 27), /* GMAC0 TXD2 */
	GEMINI_CFGPIN(240, GLOBAL_GMAC0_DATA_SKEW, 28, 31), /* GMAC0 TXD3 */
	GEMINI_CFGPIN(262, GLOBAL_GMAC1_DATA_SKEW, 0, 3), /* GMAC1 RXD0 */
	GEMINI_CFGPIN(244, GLOBAL_GMAC1_DATA_SKEW, 4, 7), /* GMAC1 RXD1 */
	GEMINI_CFGPIN(317, GLOBAL_GMAC1_DATA_SKEW, 8, 11), /* GMAC1 RXD2 */
	GEMINI_CFGPIN(299, GLOBAL_GMAC1_DATA_SKEW, 12, 15), /* GMAC1 RXD3 */
	GEMINI_CFGPIN(261, GLOBAL_GMAC1_DATA_SKEW, 16, 19), /* GMAC1 TXD0 */
	GEMINI_CFGPIN(279, GLOBAL_GMAC1_DATA_SKEW, 20, 23), /* GMAC1 TXD1 */
	GEMINI_CFGPIN(297, GLOBAL_GMAC1_DATA_SKEW, 24, 27), /* GMAC1 TXD2 */
	GEMINI_CFGPIN(315, GLOBAL_GMAC1_DATA_SKEW, 28, 31), /* GMAC1 TXD3 */
};

static const struct gemini_pin_conf gemini_confs_3516[] = {
	GEMINI_CFGPIN(347, GLOBAL_GMAC_CTRL_SKEW, 0, 3), /* GMAC0 RXDV */
	GEMINI_CFGPIN(386, GLOBAL_GMAC_CTRL_SKEW, 4, 7), /* GMAC0 RXC */
	GEMINI_CFGPIN(307, GLOBAL_GMAC_CTRL_SKEW, 8, 11), /* GMAC0 TXEN */
	GEMINI_CFGPIN(327, GLOBAL_GMAC_CTRL_SKEW, 12, 15), /* GMAC0 TXC */
	GEMINI_CFGPIN(309, GLOBAL_GMAC_CTRL_SKEW, 16, 19), /* GMAC1 RXDV */
	GEMINI_CFGPIN(390, GLOBAL_GMAC_CTRL_SKEW, 20, 23), /* GMAC1 RXC */
	GEMINI_CFGPIN(370, GLOBAL_GMAC_CTRL_SKEW, 24, 27), /* GMAC1 TXEN */
	GEMINI_CFGPIN(350, GLOBAL_GMAC_CTRL_SKEW, 28, 31), /* GMAC1 TXC */
	GEMINI_CFGPIN(367, GLOBAL_GMAC0_DATA_SKEW, 0, 3), /* GMAC0 RXD0 */
	GEMINI_CFGPIN(348, GLOBAL_GMAC0_DATA_SKEW, 4, 7), /* GMAC0 RXD1 */
	GEMINI_CFGPIN(387, GLOBAL_GMAC0_DATA_SKEW, 8, 11), /* GMAC0 RXD2 */
	GEMINI_CFGPIN(328, GLOBAL_GMAC0_DATA_SKEW, 12, 15), /* GMAC0 RXD3 */
	GEMINI_CFGPIN(306, GLOBAL_GMAC0_DATA_SKEW, 16, 19), /* GMAC0 TXD0 */
	GEMINI_CFGPIN(325, GLOBAL_GMAC0_DATA_SKEW, 20, 23), /* GMAC0 TXD1 */
	GEMINI_CFGPIN(346, GLOBAL_GMAC0_DATA_SKEW, 24, 27), /* GMAC0 TXD2 */
	GEMINI_CFGPIN(326, GLOBAL_GMAC0_DATA_SKEW, 28, 31), /* GMAC0 TXD3 */
	GEMINI_CFGPIN(391, GLOBAL_GMAC1_DATA_SKEW, 0, 3), /* GMAC1 RXD0 */
	GEMINI_CFGPIN(351, GLOBAL_GMAC1_DATA_SKEW, 4, 7), /* GMAC1 RXD1 */
	GEMINI_CFGPIN(310, GLOBAL_GMAC1_DATA_SKEW, 8, 11), /* GMAC1 RXD2 */
	GEMINI_CFGPIN(371, GLOBAL_GMAC1_DATA_SKEW, 12, 15), /* GMAC1 RXD3 */
	GEMINI_CFGPIN(329, GLOBAL_GMAC1_DATA_SKEW, 16, 19), /* GMAC1 TXD0 */
	GEMINI_CFGPIN(389, GLOBAL_GMAC1_DATA_SKEW, 20, 23), /* GMAC1 TXD1 */
	GEMINI_CFGPIN(369, GLOBAL_GMAC1_DATA_SKEW, 24, 27), /* GMAC1 TXD2 */
	GEMINI_CFGPIN(308, GLOBAL_GMAC1_DATA_SKEW, 28, 31), /* GMAC1 TXD3 */
};

static const struct gemini_pin_conf *gemini_get_pin_conf(struct gemini_pmx *pmx,
							 unsigned int pin)
{
	const struct gemini_pin_conf *retconf;
	int i;

	for (i = 0; i < pmx->nconfs; i++) {
		retconf = &gemini_confs_3516[i];
		if (retconf->pin == pin)
			return retconf;
	}
	return NULL;
}

static int gemini_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
			      unsigned long *config)
{
	struct gemini_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
	enum pin_config_param param = pinconf_to_config_param(*config);
	const struct gemini_pin_conf *conf;
	u32 val;

	switch (param) {
	case PIN_CONFIG_SKEW_DELAY:
		conf = gemini_get_pin_conf(pmx, pin);
		if (!conf)
			return -ENOTSUPP;
		regmap_read(pmx->map, conf->reg, &val);
		val &= conf->mask;
		val >>= (ffs(conf->mask) - 1);
		*config = pinconf_to_config_packed(PIN_CONFIG_SKEW_DELAY, val);
		break;
	default:
		return -ENOTSUPP;
	}

	return 0;
}

static int gemini_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
			      unsigned long *configs, unsigned int num_configs)
{
	struct gemini_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
	const struct gemini_pin_conf *conf;
	enum pin_config_param param;
	u32 arg;
	int ret = 0;
	int i;

	for (i = 0; i < num_configs; i++) {
		param = pinconf_to_config_param(configs[i]);
		arg = pinconf_to_config_argument(configs[i]);

		switch (param) {
		case PIN_CONFIG_SKEW_DELAY:
			if (arg > 0xf)
				return -EINVAL;
			conf = gemini_get_pin_conf(pmx, pin);
			if (!conf) {
				dev_err(pmx->dev,
					"invalid pin for skew delay %d\n", pin);
				return -ENOTSUPP;
			}
			arg <<= (ffs(conf->mask) - 1);
			dev_dbg(pmx->dev,
				"set pin %d to skew delay mask %08x, val %08x\n",
				pin, conf->mask, arg);
			regmap_update_bits(pmx->map, conf->reg, conf->mask, arg);
			break;
		default:
			dev_err(pmx->dev, "Invalid config param %04x\n", param);
			return -ENOTSUPP;
		}
	}

	return ret;
}

static const struct pinconf_ops gemini_pinconf_ops = {
	.pin_config_get = gemini_pinconf_get,
	.pin_config_set = gemini_pinconf_set,
	.is_generic = true,
};

static struct pinctrl_desc gemini_pmx_desc = {
	.name = DRIVER_NAME,
	.pctlops = &gemini_pctrl_ops,
	.pmxops = &gemini_pmx_ops,
	.confops = &gemini_pinconf_ops,
	.owner = THIS_MODULE,
};

@@ -2249,11 +2415,15 @@ static int gemini_pmx_probe(struct platform_device *pdev)
	val &= 0xffff;
	if (val == 0x3512) {
		pmx->is_3512 = true;
		pmx->confs = gemini_confs_3512;
		pmx->nconfs = ARRAY_SIZE(gemini_confs_3512);
		gemini_pmx_desc.pins = gemini_3512_pins;
		gemini_pmx_desc.npins = ARRAY_SIZE(gemini_3512_pins);
		dev_info(dev, "detected 3512 chip variant\n");
	} else if (val == 0x3516) {
		pmx->is_3516 = true;
		pmx->confs = gemini_confs_3516;
		pmx->nconfs = ARRAY_SIZE(gemini_confs_3516);
		gemini_pmx_desc.pins = gemini_3516_pins;
		gemini_pmx_desc.npins = ARRAY_SIZE(gemini_3516_pins);
		dev_info(dev, "detected 3516 chip variant\n");