diff --git a/drivers/gpio/npcm_sgpio.c b/drivers/gpio/npcm_sgpio.c index 14e28f5c359f..d9180485f4cd 100644 --- a/drivers/gpio/npcm_sgpio.c +++ b/drivers/gpio/npcm_sgpio.c @@ -6,30 +6,44 @@ #include #include #include +#include #include +#include #define MAX_NR_HW_SGPIO 64 -#define NPCM_CLK_MHZ 8000000 +#define NPCM_SIOX1 24 +#define NPCM_SIOX2 25 -#define NPCM_IOXCFG1 0x2A - -#define NPCM_IOXCTS 0x28 -#define NPCM_IOXCTS_IOXIF_EN BIT(7) -#define NPCM_IOXCTS_RD_MODE GENMASK(2, 1) +#define NPCM_IOXCTS 0x28 +#define NPCM_IOXCTS_IOXIF_EN BIT(7) +#define NPCM_IOXCTS_RD_MODE GENMASK(2, 1) #define NPCM_IOXCTS_RD_MODE_PERIODIC BIT(2) +#define NPCM_IOXCFG1 0x2A #define NPCM_IOXCFG2 0x2B #define NPCM_IOXCFG2_PORT GENMASK(3, 0) #define GPIO_BANK(x) ((x) / 8) #define GPIO_BIT(x) ((x) % 8) +#define WD0RCR 0x38 +#define WD1RCR 0x3c +#define WD2RCR 0x40 +#define SWRSTC1 0x44 +#define SWRSTC2 0x48 +#define SWRSTC3 0x4c +#define TIPRSTC 0x50 +#define CORSTC 0x5c + struct npcm_sgpio_priv { void __iomem *base; + struct regmap *rst_regmap; u32 nin_sgpio; u32 nout_sgpio; u32 in_port; u32 out_port; + u8 persist[8]; + u8 siox_num; }; struct npcm_sgpio_bank { @@ -189,8 +203,12 @@ static int npcm_sgpio_get_value(struct udevice *dev, unsigned int offset) static int npcm_sgpio_set_value(struct udevice *dev, unsigned int offset, int value) { + struct npcm_sgpio_priv *priv = dev_get_priv(dev); + u8 check= priv->persist[GPIO_BANK(offset)]; + + if ( !!(check & BIT(GPIO_BIT(offset))) ==0) + return npcm_sgpio_direction_output(dev, offset, value); - return npcm_sgpio_direction_output(dev, offset, value); } static int npcm_sgpio_get_function(struct udevice *dev, unsigned int offset) @@ -218,12 +236,10 @@ static void npcm_sgpio_setup_enable(struct npcm_sgpio_priv *gpio, bool enable) iowrite8(reg, gpio->base + NPCM_IOXCTS); } -static int npcm_sgpio_init_port(struct udevice *dev) +static void npcm_sgpio_set_port(struct udevice *dev) { struct npcm_sgpio_priv *priv = dev_get_priv(dev); - u8 in_port, out_port, set_port, reg, set_clk; - - npcm_sgpio_setup_enable(priv, false); + u8 in_port, out_port, set_port; in_port = GPIO_BANK(priv->nin_sgpio); if (GPIO_BIT(priv->nin_sgpio) > 0) @@ -236,7 +252,17 @@ static int npcm_sgpio_init_port(struct udevice *dev) priv->in_port = in_port; priv->out_port = out_port; - set_port = (out_port & NPCM_IOXCFG2_PORT) << 4 | (in_port & NPCM_IOXCFG2_PORT); +} + +static int npcm_sgpio_init_port(struct udevice *dev) +{ + struct npcm_sgpio_priv *priv = dev_get_priv(dev); + u8 set_port, reg, set_clk; + + npcm_sgpio_setup_enable(priv, false); + + + set_port = (priv->out_port & NPCM_IOXCFG2_PORT) << 4 | (priv->in_port & NPCM_IOXCFG2_PORT); set_clk=0x07; iowrite8(set_port, priv->base + NPCM_IOXCFG2); @@ -246,6 +272,62 @@ static int npcm_sgpio_init_port(struct udevice *dev) return reg == set_port ? 0 : -EINVAL; } +static int npcm_sgpio_reset_persist(struct udevice *dev, uint enable) +{ + struct npcm_sgpio_priv *priv = dev_get_priv(dev); + u8 num; + + if (priv->siox_num==1) + num = NPCM_SIOX2; + else + num = NPCM_SIOX1; + + if(enable) { + regmap_update_bits(priv->rst_regmap, WD0RCR, BIT(num), 0); + regmap_update_bits(priv->rst_regmap, WD1RCR, BIT(num), 0); + regmap_update_bits(priv->rst_regmap, WD2RCR, BIT(num), 0); + regmap_update_bits(priv->rst_regmap, CORSTC, BIT(num), 0); + regmap_update_bits(priv->rst_regmap, SWRSTC1, BIT(num), 0); + regmap_update_bits(priv->rst_regmap, SWRSTC2, BIT(num), 0); + regmap_update_bits(priv->rst_regmap, SWRSTC3, BIT(num), 0); + regmap_update_bits(priv->rst_regmap, TIPRSTC, BIT(num), 0); + } + +} +static bool is_gpio_persist(struct udevice *dev) +{ + struct npcm_sgpio_priv *priv = dev_get_priv(dev); + u32 val; + int status; + char *name =ofnode_get_name(dev_ofnode(dev)); + + status = npcm_get_reset_status(); + + if (status & PORST) + return false; + if (status & CORST) + regmap_read(priv->rst_regmap, CORSTC, &val); + else if (status & WD0RST) + regmap_read(priv->rst_regmap, WD0RCR, &val); + else if (status & WD1RST) + regmap_read(priv->rst_regmap, WD1RCR, &val); + else if (status & WD2RST) + regmap_read(priv->rst_regmap, WD2RCR, &val); + else if (status & SW1RST) + regmap_read(priv->rst_regmap, SWRSTC1, &val); + else if (status & SW2RST) + regmap_read(priv->rst_regmap, SWRSTC2, &val); + else if (status & SW3RST) + regmap_read(priv->rst_regmap, SWRSTC3, &val); + else if (status & TIPRST) + regmap_read(priv->rst_regmap, TIPRSTC, &val); + + if (priv->siox_num ==1) + return (val && BIT(NPCM_SIOX2)); + else + return (val && BIT(NPCM_SIOX1)); + +} static const struct dm_gpio_ops npcm_sgpio_ops = { .direction_input = npcm_sgpio_direction_input, @@ -259,23 +341,59 @@ static int npcm_sgpio_probe(struct udevice *dev) { struct npcm_sgpio_priv *priv = dev_get_priv(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - int rc; + int rc, i; + ofnode node; + u32 val[2]; priv->base = dev_read_addr_ptr(dev); + priv->rst_regmap = syscon_regmap_lookup_by_phandle(dev, "syscon-rst"); + if (IS_ERR(priv->rst_regmap)) + return -EINVAL; + ofnode_read_u32(dev_ofnode(dev), "nuvoton,input-ngpios", &priv->nin_sgpio); ofnode_read_u32(dev_ofnode(dev), "nuvoton,output-ngpios", &priv->nout_sgpio); if (priv->nin_sgpio > MAX_NR_HW_SGPIO || priv->nout_sgpio > MAX_NR_HW_SGPIO) return -EINVAL; - rc = npcm_sgpio_init_port(dev); - if (rc < 0) - return rc; + if (!strcmp(ofnode_get_name(dev_ofnode(dev)), "sgpio2@102000")) + priv->siox_num=1; + else if (!strcmp(ofnode_get_name(dev_ofnode(dev)), "sgpio1@101000")) + priv->siox_num=0; + else + return -EINVAL; + npcm_sgpio_set_port(dev); uc_priv->gpio_count = priv->nin_sgpio + priv->nout_sgpio; uc_priv->bank_name = dev->name; - npcm_sgpio_setup_enable(priv, true); + if (is_gpio_persist(dev)) { + ofnode_for_each_subnode(node, dev_ofnode(dev)) { + if(ofnode_read_bool(node, "persist-enable")) { + rc = ofnode_read_u32_array(node, "gpios", val,2); + if (rc ==0) { + priv->persist[GPIO_BANK(val[0])] = priv->persist[GPIO_BANK(val[0])] | BIT(GPIO_BIT(val[0])); + } + } + } + for(i=0; i< priv->nout_sgpio; i++) + npcm_sgpio_set_value(dev, i, 0); + } + else { + rc = npcm_sgpio_init_port(dev); + if (rc < 0) + return rc; + + ofnode_for_each_subnode(node, dev_ofnode(dev)) { + if(ofnode_read_bool(node, "persist-enable")) + npcm_sgpio_reset_persist(dev,1); + } + + for(i=0; i< priv->nout_sgpio; i++) + npcm_sgpio_set_value(dev, i, 0); + + npcm_sgpio_setup_enable(priv, true); + } return 0; }