aboutsummaryrefslogtreecommitdiff
path: root/plat/mediatek/common/drivers/pmic_wrap/pmic_wrap_init_v2.c
blob: d9a79c4949e9e62ce0b8aea0f3d43ccf5d798714 (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
/*
 * Copyright (c) 2020, MediaTek Inc. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>

#include "platform_def.h"
#include "pmic_wrap_init.h"

/* pmic wrap module wait_idle and read polling interval (in microseconds) */
enum pwrap_polling_interval {
	WAIT_IDLE_POLLING_DELAY_US	= 1,
	READ_POLLING_DELAY_US		= 2
};

static uint32_t pwrap_check_idle(void *wacs_register, uint32_t timeout_us)
{
	uint32_t reg_rdata = 0U, retry;

	retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
		WAIT_IDLE_POLLING_DELAY_US;
	while (retry != 0) {
		udelay(WAIT_IDLE_POLLING_DELAY_US);
		reg_rdata = mmio_read_32((uintptr_t)wacs_register);
		/* if last read command timeout,clear vldclr bit
		 * read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
		 * write:FSM_REQ-->idle
		 */
		switch (GET_WACS_FSM(reg_rdata)) {
		case SWINF_FSM_WFVLDCLR:
			mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
			INFO("WACS_FSM = SWINF_FSM_WFVLDCLR\n");
			break;
		case SWINF_FSM_WFDLE:
			INFO("WACS_FSM = SWINF_FSM_WFDLE\n");
			break;
		case SWINF_FSM_REQ:
			INFO("WACS_FSM = SWINF_FSM_REQ\n");
			break;
		case SWINF_FSM_IDLE:
			goto done;
		default:
			break;
		}
		retry--;
	};

done:
	if (retry == 0) {
		/* timeout */
		return E_PWR_WAIT_IDLE_TIMEOUT;
	}

	return 0U;
}

static uint32_t pwrap_check_vldclr(void *wacs_register, uint32_t timeout_us)
{
	uint32_t reg_rdata = 0U, retry;

	retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
	while (retry != 0) {
		udelay(READ_POLLING_DELAY_US);
		reg_rdata = mmio_read_32((uintptr_t)wacs_register);
		if (GET_WACS_FSM(reg_rdata) == SWINF_FSM_WFVLDCLR) {
			break;
		}
		retry--;
	};

	if (retry == 0) {
		/* timeout */
		return E_PWR_WAIT_IDLE_TIMEOUT;
	}

	return 0U;
}

static int32_t pwrap_wacs2(uint32_t write, uint32_t adr, uint32_t wdata,
			   uint32_t *rdata, uint32_t init_check)
{
	uint32_t reg_rdata, return_value;

	if (init_check != 0) {
		if ((mmio_read_32((uintptr_t)&mtk_pwrap->init_done) & 0x1) == 0) {
			ERROR("initialization isn't finished\n");
			return E_PWR_NOT_INIT_DONE;
		}
	}

	/* Wait for Software Interface FSM state to be IDLE. */
	return_value = pwrap_check_idle(&mtk_pwrap->wacs2_sta,
					PWRAP_WAIT_IDLE_US);
	if (return_value != 0) {
		return return_value;
	}

	/* Set the write data */
	if (write == 1) {
		/* Set the write data. */
		mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_wdata, wdata);
	}

	/* Send the command. */
	mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_cmd, (write << 29) | adr);

	if (write == 0) {
		/*
		 * Wait for Software Interface FSM state to be WFVLDCLR,
		 * read the data and clear the valid flag.
		 */
		return_value = pwrap_check_vldclr(&mtk_pwrap->wacs2_sta,
						  PWRAP_READ_US);
		if (return_value != 0) {
			return return_value;
		}

		if (rdata == NULL) {
			return E_PWR_INVALID_ARG;
		}

		reg_rdata = mmio_read_32((uintptr_t)&mtk_pwrap->wacs2_rdata);
		*rdata = reg_rdata;
		mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
	}

	return return_value;
}

/* external API for pmic_wrap user */
int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
{
	return pwrap_wacs2(0, adr, 0, rdata, 1);
}

int32_t pwrap_write(uint32_t adr, uint32_t wdata)
{
	return pwrap_wacs2(1, adr, wdata, 0, 1);
}