aboutsummaryrefslogtreecommitdiff
path: root/drivers/renesas/rcar/watchdog/swdt.c
blob: 42f865349566547ca8830d6823fcb05eafcba817 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/gicv2.h>
#include <lib/mmio.h>

#include "rcar_def.h"

extern void gicd_set_icenabler(uintptr_t base, unsigned int id);

#define RST_BASE			(0xE6160000U)
#define RST_WDTRSTCR			(RST_BASE + 0x0054U)
#define SWDT_BASE			(0xE6030000U)
#define SWDT_WTCNT			(SWDT_BASE + 0x0000U)
#define SWDT_WTCSRA			(SWDT_BASE + 0x0004U)
#define SWDT_WTCSRB			(SWDT_BASE + 0x0008U)
#define SWDT_GICD_BASE			(0xF1010000U)
#define SWDT_GICC_BASE			(0xF1020000U)
#define SWDT_GICD_CTLR			(SWDT_GICD_BASE + 0x0000U)
#define SWDT_GICD_IGROUPR		(SWDT_GICD_BASE + 0x0080U)
#define SWDT_GICD_ISPRIORITYR		(SWDT_GICD_BASE + 0x0400U)
#define SWDT_GICC_CTLR			(SWDT_GICC_BASE + 0x0000U)
#define SWDT_GICC_PMR			(SWDT_GICC_BASE + 0x0004U)
#define SWDT_GICD_ITARGETSR		(SWDT_GICD_BASE + 0x0800U)
#define IGROUPR_NUM			(16U)
#define ISPRIORITY_NUM			(128U)
#define ITARGET_MASK			(0x03U)

#define WDTRSTCR_UPPER_BYTE		(0xA55A0000U)
#define WTCSRA_UPPER_BYTE		(0xA5A5A500U)
#define WTCSRB_UPPER_BYTE		(0xA5A5A500U)
#define WTCNT_UPPER_BYTE		(0x5A5A0000U)
#define WTCNT_RESET_VALUE		(0xF488U)
#define WTCSRA_BIT_CKS			(0x0007U)
#define WTCSRB_BIT_CKS			(0x003FU)
#define SWDT_RSTMSK			(1U << 1U)
#define WTCSRA_WOVFE			(1U << 3U)
#define WTCSRA_WRFLG			(1U << 5U)
#define SWDT_ENABLE			(1U << 7U)

#define WDTRSTCR_MASK_ALL		(0x0000FFFFU)
#define WTCSRA_MASK_ALL			(0x000000FFU)
#define WTCNT_INIT_DATA			(WTCNT_UPPER_BYTE + WTCNT_RESET_VALUE)
#define WTCSRA_INIT_DATA		(WTCSRA_UPPER_BYTE + 0x0FU)
#define WTCSRB_INIT_DATA		(WTCSRB_UPPER_BYTE + 0x21U)

#define WTCNT_COUNT_8p13k		(0x10000U - 40687U)
#define WTCNT_COUNT_8p13k_H3VER10	(0x10000U - 20343U)
#define WTCNT_COUNT_8p22k		(0x10000U - 41115U)
#define WTCNT_COUNT_7p81k		(0x10000U - 39062U)
#define WTCSRA_CKS_DIV16		(0x00000002U)

static void swdt_disable(void)
{
	uint32_t rmsk;

	rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL;
	rmsk |= SWDT_RSTMSK;
	mmio_write_32(RST_WDTRSTCR, WDTRSTCR_UPPER_BYTE | rmsk);

	mmio_write_32(SWDT_WTCNT, WTCNT_INIT_DATA);
	mmio_write_32(SWDT_WTCSRA, WTCSRA_INIT_DATA);
	mmio_write_32(SWDT_WTCSRB, WTCSRB_INIT_DATA);

	/* Set the interrupt clear enable register */
	gicd_set_icenabler(RCAR_GICD_BASE, ARM_IRQ_SEC_WDT);
}

void rcar_swdt_init(void)
{
	uint32_t rmsk, sr;
#if (RCAR_LSI != RCAR_E3)
	uint32_t reg, val, product_cut, chk_data;

	reg = mmio_read_32(RCAR_PRR);
	product_cut = reg & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);

	reg = mmio_read_32(RCAR_MODEMR);
	chk_data = reg & CHECK_MD13_MD14;
#endif
	/* stop watchdog */
	if (mmio_read_32(SWDT_WTCSRA) & SWDT_ENABLE)
		mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE);

	mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE |
		      WTCSRA_WOVFE | WTCSRA_CKS_DIV16);

#if (RCAR_LSI == RCAR_E3)
	mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_7p81k);
#else
	val = WTCNT_UPPER_BYTE;

	switch (chk_data) {
	case MD14_MD13_TYPE_0:
	case MD14_MD13_TYPE_2:
		val |= WTCNT_COUNT_8p13k;
		break;
	case MD14_MD13_TYPE_1:
		val |= WTCNT_COUNT_8p22k;
		break;
	case MD14_MD13_TYPE_3:
		val |= product_cut == (RCAR_PRODUCT_H3 | RCAR_CUT_VER10) ?
		    WTCNT_COUNT_8p13k_H3VER10 : WTCNT_COUNT_8p13k;
		break;
	default:
		ERROR("MODEMR ERROR value = %x\n", chk_data);
		panic();
		break;
	}

	mmio_write_32(SWDT_WTCNT, val);
#endif
	rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL;
	rmsk |= SWDT_RSTMSK | WDTRSTCR_UPPER_BYTE;
	mmio_write_32(RST_WDTRSTCR, rmsk);

	while ((mmio_read_8(SWDT_WTCSRA) & WTCSRA_WRFLG) != 0U)
		;

	/* Start the System WatchDog Timer */
	sr = mmio_read_32(SWDT_WTCSRA) & WTCSRA_MASK_ALL;
	mmio_write_32(SWDT_WTCSRA, (WTCSRA_UPPER_BYTE | sr | SWDT_ENABLE));
}

void rcar_swdt_release(void)
{
	uintptr_t itarget = SWDT_GICD_ITARGETSR +
	    (ARM_IRQ_SEC_WDT & ~ITARGET_MASK);
	uint32_t i;

	write_daifset(DAIF_FIQ_BIT);
	swdt_disable();
	gicv2_cpuif_disable();

	for (i = 0; i < IGROUPR_NUM; i++)
		mmio_write_32(SWDT_GICD_IGROUPR + i * 4, 0U);

	for (i = 0; i < ISPRIORITY_NUM; i++)
		mmio_write_32(SWDT_GICD_ISPRIORITYR + i * 4, 0U);

	mmio_write_32(itarget, 0U);
	mmio_write_32(SWDT_GICD_CTLR, 0U);
	mmio_write_32(SWDT_GICC_CTLR, 0U);
	mmio_write_32(SWDT_GICC_PMR, 0U);
}

void rcar_swdt_exec(uint64_t p)
{
	gicv2_end_of_interrupt(ARM_IRQ_SEC_WDT);
	rcar_swdt_release();
	ERROR("\n");
	ERROR("System WDT overflow, occured address is %p\n", (void *)p);
	panic();
}