* @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 {
int reset_bit;
int ack_offset;
int ack_bit;
+ int deassert_cnt;
};
/**
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. */
#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),
#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),
/* 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),
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;
/* 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);