]> git.sur5r.net Git - u-boot/blobdiff - drivers/reset/sti-reset.c
reset: sti: add deassert counter in reset channel descriptor
[u-boot] / drivers / reset / sti-reset.c
index 0c32a3d8c9eef6effe7972285bc554d416744410..a79708cde2800a7169e905396afb808b15aa6767 100644 (file)
@@ -30,6 +30,8 @@ struct sti_reset {
  * @reset_bit: Bit number in reset register.
  * @ack_offset: Ack reset register offset in syscon bank.
  * @ack_bit: Bit number in Ack reset register.
+ * @deassert_cnt: incremented when reset is deasserted, reset can only be
+ *                asserted when equal to 0
  */
 
 struct syscfg_reset_channel_data {
@@ -38,6 +40,7 @@ struct syscfg_reset_channel_data {
        int reset_bit;
        int ack_offset;
        int ack_bit;
+       int deassert_cnt;
 };
 
 /**
@@ -54,7 +57,7 @@ struct syscfg_reset_controller_data {
        bool wait_for_ack;
        bool active_low;
        int nr_channels;
-       const struct syscfg_reset_channel_data *channels;
+       struct syscfg_reset_channel_data *channels;
 };
 
 /* STiH407 Peripheral powerdown definitions. */
@@ -102,7 +105,7 @@ static const char stih407_lpm[] = "st,stih407-lpm-syscfg";
 #define SYSSTAT_4520   0x820
 #define SYSCFG_4002    0x8
 
-static const struct syscfg_reset_channel_data stih407_powerdowns[] = {
+static struct syscfg_reset_channel_data stih407_powerdowns[] = {
        [STIH407_EMISS_POWERDOWN] = STIH407_PDN_0(1),
        [STIH407_NAND_POWERDOWN] = STIH407_PDN_0(0),
        [STIH407_USB3_POWERDOWN] = STIH407_PDN_1(6),
@@ -122,7 +125,7 @@ static const struct syscfg_reset_channel_data stih407_powerdowns[] = {
 
 #define LPM_SYSCFG_1   0x4     /* Softreset IRB & SBC UART */
 
-static const struct syscfg_reset_channel_data stih407_softresets[] = {
+static struct syscfg_reset_channel_data stih407_softresets[] = {
        [STIH407_ETH1_SOFTRESET] = STIH407_SRST_SBC(SYSCFG_4002, 4),
        [STIH407_MMC1_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 3),
        [STIH407_USB2_PORT0_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 28),
@@ -161,7 +164,7 @@ static const struct syscfg_reset_channel_data stih407_softresets[] = {
 /* PicoPHY reset/control */
 #define SYSCFG_5061    0x0f4
 
-static const struct syscfg_reset_channel_data stih407_picophyresets[] = {
+static struct syscfg_reset_channel_data stih407_picophyresets[] = {
        [STIH407_PICOPHY0_RESET] = STIH407_SRST_CORE(SYSCFG_5061, 5),
        [STIH407_PICOPHY1_RESET] = STIH407_SRST_CORE(SYSCFG_5061, 6),
        [STIH407_PICOPHY2_RESET] = STIH407_SRST_CORE(SYSCFG_5061, 7),
@@ -223,7 +226,7 @@ static int sti_reset_program_hw(struct reset_ctl *reset_ctl, int assert)
        struct udevice *dev = reset_ctl->dev;
        struct syscfg_reset_controller_data *reset_desc =
                (struct syscfg_reset_controller_data *)(dev->driver_data);
-       struct syscfg_reset_channel_data ch;
+       struct syscfg_reset_channel_data *ch;
        phys_addr_t base;
        u32 ctrl_val = reset_desc->active_low ? !assert : !!assert;
        void __iomem *reg;
@@ -235,19 +238,35 @@ static int sti_reset_program_hw(struct reset_ctl *reset_ctl, int assert)
        /* get reset sysconf register base address */
        base = sti_reset_get_regmap(reset_desc->channels[reset_ctl->id].compatible);
 
-       ch = reset_desc->channels[reset_ctl->id];
-       reg = (void __iomem *)base + ch.reset_offset;
+       ch = &reset_desc->channels[reset_ctl->id];
+
+       /* check the deassert counter to assert reset when it reaches 0 */
+       if (!assert) {
+               ch->deassert_cnt++;
+               if (ch->deassert_cnt > 1)
+                       return 0;
+       } else {
+               if (ch->deassert_cnt > 0) {
+                       ch->deassert_cnt--;
+                       if (ch->deassert_cnt > 0)
+                               return 0;
+               } else
+                       error("Reset balancing error: reset_ctl=%p dev=%p id=%lu\n",
+                             reset_ctl, reset_ctl->dev, reset_ctl->id);
+       }
+
+       reg = (void __iomem *)base + ch->reset_offset;
 
        if (ctrl_val)
-               generic_set_bit(ch.reset_bit, reg);
+               generic_set_bit(ch->reset_bit, reg);
        else
-               generic_clear_bit(ch.reset_bit, reg);
+               generic_clear_bit(ch->reset_bit, reg);
 
        if (!reset_desc->wait_for_ack)
                return 0;
 
-       reg = (void __iomem *)base + ch.ack_offset;
-       if (wait_for_bit(__func__, reg, BIT(ch.ack_bit), ctrl_val,
+       reg = (void __iomem *)base + ch->ack_offset;
+       if (wait_for_bit(__func__, reg, BIT(ch->ack_bit), ctrl_val,
                         1000, false)) {
                error("Stuck on waiting ack reset_ctl=%p dev=%p id=%lu\n",
                      reset_ctl, reset_ctl->dev, reset_ctl->id);