// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2022 StarFive Technology Co., Ltd.
 * Author: Yanhong Wang<yanhong.wang@starfivetech.com>
 */

#include <asm/io.h>

#include "starfive_ddr.h"

static const struct ddr_reg_cfg ddr_start_cfg[] = {
	{89,	0xffffff00,	0x00000051,	(OFFSET_SEL | REGCLRSETALL)},
	{78,	0xfffffcff,	0x0,		(OFFSET_SEL | REGCLRSETALL)},
	{345,	0xffffff00,	0x00000051,	(OFFSET_SEL | REGCLRSETALL)},
	{334,	0xfffffcff,	0x0,		(OFFSET_SEL | REGCLRSETALL)},
	{601,	0xffffff00,	0x00000051,	(OFFSET_SEL | REGCLRSETALL)},
	{590,	0xfffffcff,	0x0,		(OFFSET_SEL | REGCLRSETALL)},
	{857,	0xffffff00,	0x00000051,	(OFFSET_SEL | REGCLRSETALL)},
	{846,	0xfffffcff,	0x0,		(OFFSET_SEL | REGCLRSETALL)},
	{1793,	0xfffffeff,	0x0,		(OFFSET_SEL | REGCLRSETALL)},
	{1793,	0xfffcffff,	0x0,		(OFFSET_SEL | REGCLRSETALL)},
	{125,	0xfff0ffff,	0x00010000,	(OFFSET_SEL | REGCLRSETALL)},
	{102,	0xfffffffc,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{105,	0xffffffe0,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{92,	0xfffffffe,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{94,	0xffffe0ff,	0x00000200,	(OFFSET_SEL | REGCLRSETALL)},
	{96,	0xfffff0ff,	0x00000400,	(OFFSET_SEL | REGCLRSETALL)},
	{89,	0xffffff00,	0x00000051,	(OFFSET_SEL | REGCLRSETALL)},
	{381,	0xfff0ffff,	0x00010000,	(OFFSET_SEL | REGCLRSETALL)},
	{358,	0xfffffffc,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{361,	0xffffffe0,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{348,	0xfffffffe,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{350,	0xffffe0ff,	0x00000200,	(OFFSET_SEL | REGCLRSETALL)},
	{352,	0xfffff0ff,	0x00000400,	(OFFSET_SEL | REGCLRSETALL)},
	{345,	0xffffff00,	0x00000051,	(OFFSET_SEL | REGCLRSETALL)},
	{637,	0xfff0ffff,	0x00010000,	(OFFSET_SEL | REGCLRSETALL)},
	{614,	0xfffffffc,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{617,	0xffffffe0,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{604,	0xfffffffe,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{606,	0xffffe0ff,	0x00000200,	(OFFSET_SEL | REGCLRSETALL)},
	{608,	0xfffff0ff,	0x00000400,	(OFFSET_SEL | REGCLRSETALL)},
	{601,	0xffffff00,	0x00000051,	(OFFSET_SEL | REGCLRSETALL)},
	{893,	0xfff0ffff,	0x00010000,	(OFFSET_SEL | REGCLRSETALL)},
	{870,	0xfffffffc,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{873,	0xffffffe0,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{860,	0xfffffffe,	0x00000001,	(OFFSET_SEL | REGCLRSETALL)},
	{862,	0xffffe0ff,	0x00000200,	(OFFSET_SEL | REGCLRSETALL)},
	{864,	0xfffff0ff,	0x00000400,	(OFFSET_SEL | REGCLRSETALL)},
	{857,	0xffffff00,	0x00000051,	(OFFSET_SEL | REGCLRSETALL)},
	{1895,	0xffffe000,	0x00001342,	(OFFSET_SEL | REGCLRSETALL)},
	{1835,	0xfffff0ff,	0x00000200,	(OFFSET_SEL | REGCLRSETALL)},
	{1793,	0xfffffeff,	0x00000100,	(OFFSET_SEL | REGCLRSETALL)},
	{62,	0xfffffeff,	0x0,		REGCLRSETALL},
	{66,	0xfffffeff,	0x0,		REGCLRSETALL},
	{166,	0xffffff80,	0x00000001,	REGCLRSETALL},
	{62,	0xfff0ffff,	0x00010000,	REGCLRSETALL},
	{62,	0xf0ffffff,	0x01000000,	REGCLRSETALL},
	{166,	0xffff80ff,	0x00000100,	REGCLRSETALL},
	{179,	0xff80ffff,	0x00010000,	REGCLRSETALL},
	{67,	0xffe0ffff,	0x00010000,	REGCLRSETALL},
	{67,	0xe0ffffff,	0x01000000,	REGCLRSETALL},
	{179,	0x80ffffff,	0x01000000,	REGCLRSETALL},
	{166,	0xff80ffff,	0x00010000,	REGCLRSETALL},
	{62,	0xfff0ffff,	0x00010000,	REGCLRSETALL},
	{62,	0xf0ffffff,	0x01000000,	REGCLRSETALL},
	{166,	0x80ffffff,	0x01000000,	REGCLRSETALL},
	{182,	0xff80ffff,	0x00010000,	REGCLRSETALL},
	{67,	0xffe0ffff,	0x00010000,	REGCLRSETALL},
	{67,	0xe0ffffff,	0x01000000,	REGCLRSETALL},
	{182,	0x80ffffff,	0x01000000,	REGCLRSETALL},
	{167,	0xffffff80,	0x00000017,	REGCLRSETALL},
	{62,	0xfff0ffff,	0x00010000,	REGCLRSETALL},
	{62,	0xf0ffffff,	0x01000000,	REGCLRSETALL},
	{167,	0xffff80ff,	0x00001700,	REGCLRSETALL},
	{185,	0xff80ffff,	0x00200000,	REGCLRSETALL},
	{67,	0xffe0ffff,	0x00010000,	REGCLRSETALL},
	{67,	0xe0ffffff,	0x01000000,	REGCLRSETALL},
	{185,	0x80ffffff,	0x20000000,	REGCLRSETALL},
	{10,	0xffffffe0,	0x00000002,	REGCLRSETALL},
	{0,	0xfffffffe,	0x00000001,	REGCLRSETALL},
	{11,	0xfffffff0,	0x00000005,	(F_CLRSET | REG2G)},
	{247,	0xffffffff,	0x00000008,	REGCLRSETALL},
	{249,	0xffffffff,	0x00000800,	REGCLRSETALL},
	{252,	0xffffffff,	0x00000008,	REGCLRSETALL},
	{254,	0xffffffff,	0x00000800,	REGCLRSETALL},
	{281,	0xffffffff,	0x33000000,	REGCLRSETALL},
	{305,	0xffffffff,	0x33000000,	REGCLRSETALL},
	{329,	0xffffffff,	0x33000000,	REGCLRSETALL},
	{353,	0xffffffff,	0x33000000,	REGCLRSETALL},
	{289,	0xffffffff,	0x36000000,	(F_CLRSET | REG8G)},
	{313,	0xffffffff,	0x36000000,	(F_CLRSET | REG8G)},
	{337,	0xffffffff,	0x36000000,	(F_CLRSET | REG8G)},
	{361,	0xffffffff,	0x36000000,	(F_CLRSET | REG8G)},
	{289,	0xffffffff,	0x66000000,	(F_CLRSET | REG2G | REG4G)},
	{313,	0xffffffff,	0x66000000,	(F_CLRSET | REG2G | REG4G)},
	{337,	0xffffffff,	0x66000000,	(F_CLRSET | REG2G | REG4G)},
	{361,	0xffffffff,	0x66000000,	(F_CLRSET | REG2G | REG4G)},
	{282,	0xffffffff,	0x00160000,	REGCLRSETALL},
	{306,	0xffffffff,	0x00160000,	REGCLRSETALL},
	{330,	0xffffffff,	0x00160000,	REGCLRSETALL},
	{354,	0xffffffff,	0x00160000,	REGCLRSETALL},
	{290,	0xffffffff,	0x00160000,	REGCLRSETALL},
	{314,	0xffffffff,	0x00160000,	REGCLRSETALL},
	{338,	0xffffffff,	0x00160000,	REGCLRSETALL},
	{362,	0xffffffff,	0x00160000,	REGCLRSETALL},
	{282,	0xffffff00,	0x17,		REGCLRSETALL},
	{306,	0xffffff00,	0x17,		REGCLRSETALL},
	{330,	0xffffff00,	0x17,		REGCLRSETALL},
	{354,	0xffffff00,	0x17,		REGCLRSETALL},
	{290,	0xffffff00,	0x17,		REGCLRSETALL},
	{314,	0xffffff00,	0x17,		REGCLRSETALL},
	{338,	0xffffff00,	0x17,		REGCLRSETALL},
	{362,	0xffffff00,	0x17,		REGCLRSETALL},
	{282,	0xffff00ff,	0x2000,		REGCLRSETALL},
	{306,	0xffff00ff,	0x2000,		REGCLRSETALL},
	{330,	0xffff00ff,	0x2000,		REGCLRSETALL},
	{354,	0xffff00ff,	0x2000,		REGCLRSETALL},
	{290,	0xffff00ff,	0x2000,		REGCLRSETALL},
	{314,	0xffff00ff,	0x2000,		REGCLRSETALL},
	{338,	0xffff00ff,	0x2000,		REGCLRSETALL},
	{362,	0xffff00ff,	0x2000,		REGCLRSETALL},
	{65,	0xffffffff,	0x00000100,	(OFFSET_SEL | REGCLRSETALL)},
	{321,	0xffffffff,	0x00000100,	(OFFSET_SEL | REGCLRSETALL)},
	{577,	0xffffffff,	0x00000100,	(OFFSET_SEL | REGCLRSETALL)},
	{833,	0xffffffff,	0x00000100,	(OFFSET_SEL | REGCLRSETALL)},
	{96,	0x0,		0x300,		(OFFSET_SEL | REGADDSETALL)},
	{352,	0x0,		0x300,		(OFFSET_SEL | REGADDSETALL)},
	{608,	0x0,		0x300,		(OFFSET_SEL | REGADDSETALL)},
	{864,	0x0,		0x300,		(OFFSET_SEL | REGADDSETALL)},
	{96,	0xff00ffff,	0x00120000,	(OFFSET_SEL | REGCLRSETALL)},
	{352,	0xff00ffff,	0x00120000,	(OFFSET_SEL | REGCLRSETALL)},
	{608,	0xff00ffff,	0x00120000,	(OFFSET_SEL | REGCLRSETALL)},
	{864,	0xff00ffff,	0x00120000,	(OFFSET_SEL | REGCLRSETALL)},
	{33,	0xffffff00,	0x0040,		(OFFSET_SEL | REGCLRSETALL)},
	{289,	0xffffff00,	0x0040,		(OFFSET_SEL | REGCLRSETALL)},
	{545,	0xffffff00,	0x0040,		(OFFSET_SEL | REGCLRSETALL)},
	{801,	0xffffff00,	0x0040,		(OFFSET_SEL | REGCLRSETALL)},
	{1038,	0xfcffffff,	0x03000000,	(OFFSET_SEL | REGCLRSETALL)},
	{1294,	0xfcffffff,	0x03000000,	(OFFSET_SEL | REGCLRSETALL)},
	{1550,	0xfcffffff,	0x03000000,	(OFFSET_SEL | REGCLRSETALL)},
	{83,	0xffc0ffff,	0x70000,	(OFFSET_SEL | REGCLRSETALL)},
	{339,	0xffc0ffff,	0x70000,	(OFFSET_SEL | REGCLRSETALL)},
	{595,	0xffc0ffff,	0x70000,	(OFFSET_SEL | REGCLRSETALL)},
	{851,	0xffc0ffff,	0x70000,	(OFFSET_SEL | REGCLRSETALL)},
	{1062,	0xf800ffff,	0x70000,	(OFFSET_SEL | REGCLRSETALL)},
	{1318,	0xf800ffff,	0x70000,	(OFFSET_SEL | REGCLRSETALL)},
	{1574,	0xf800ffff,	0x70000,	(OFFSET_SEL | REGCLRSETALL)},
	{1892,	0xfffc0000,	0x15547,	(OFFSET_SEL | REGCLRSETALL)},
	{1893,	0xfffc0000,	0x7,		(OFFSET_SEL | REGCLRSETALL)},
	{1852,	0xffffe000,	0x07a,		(OFFSET_SEL | REGCLRSETALL)},
	{1853,	0xffffffff,	0x0100,		(OFFSET_SEL | REGCLRSETALL)},
	{1822,	0xffffffff,	0xFF,		(OFFSET_SEL | REGCLRSETALL)},
	{1896,	0xfffffc00,	0x03d5,		(OFFSET_SEL | REGCLRSETALL)},
	{91,	0xfc00ffff,	0x03d50000,	(OFFSET_SEL | REGCLRSETALL)},
	{347,	0xfc00ffff,	0x03d50000,	(OFFSET_SEL | REGCLRSETALL)},
	{603,	0xfc00ffff,	0x03d50000,	(OFFSET_SEL | REGCLRSETALL)},
	{859,	0xfc00ffff,	0x03d50000,	(OFFSET_SEL | REGCLRSETALL)},
	{1912,	0x0,		0xcc3bfc7,	(OFFSET_SEL | REGSETALL)},
	{1913,	0x0,		0xff8f,		(OFFSET_SEL | REGSETALL)},
	{1914,	0x0,		0x33f07ff,	(OFFSET_SEL | REGSETALL)},
	{1915,	0x0,		0xc3c37ff,	(OFFSET_SEL | REGSETALL)},
	{1916,	0x0,		0x1fffff10,	(OFFSET_SEL | REGSETALL)},
	{1917,	0x0,		0x230070,	(OFFSET_SEL | REGSETALL)},
	{1918,	0x0,		0x3ff7ffff,	(OFFSET_SEL | REG4G | REG2G | F_SET)},
	{1918,	0x0,		0x3ff7ffff,	(OFFSET_SEL | REG8G | F_SET)},
	{1919,	0x0,		0xe10,		(OFFSET_SEL | REGSETALL)},
	{1920,	0x0,		0x1fffffff,	(OFFSET_SEL | REGSETALL)},
	{1921,	0x0,		0x188411,	(OFFSET_SEL | REGSETALL)},
	{1922,	0x0,		0x1fffffff,	(OFFSET_SEL | REGSETALL)},
	{1923,	0x0,		0x180400,	(OFFSET_SEL | REGSETALL)},
	{1924,	0x0,		0x1fffffff,	(OFFSET_SEL | REGSETALL)},
	{1925,	0x0,		0x180400,	(OFFSET_SEL | REGSETALL)},
	{1926,	0x0,		0x1fffffcf,	(OFFSET_SEL | REGSETALL)},
	{1927,	0x0,		0x188400,	(OFFSET_SEL | REGSETALL)},
	{1928,	0x0,		0x1fffffff,	(OFFSET_SEL | REGSETALL)},
	{1929,	0x0,		0x4188411,	(OFFSET_SEL | REGSETALL)},
	{1837,	0x0,		0x24410,	(OFFSET_SEL | REGSETALL)},
	{1840,	0x0,		0x24410,	(OFFSET_SEL | REGSETALL)},
	{1842,	0x0,		0x2ffff,	(OFFSET_SEL | REGSETALL)},
	{76,	0xff0000f8,	0x00ff8f07,	(OFFSET_SEL | REGCLRSETALL)},
	{332,	0xff0000f8,	0x00ff8f07,	(OFFSET_SEL | REGCLRSETALL)},
	{588,	0xff0000f8,	0x00ff8f07,	(OFFSET_SEL | REGCLRSETALL)},
	{844,	0xff0000f8,	0x00ff8f07,	(OFFSET_SEL | REGCLRSETALL)},
	{77,	0xffff0000,	0xff8f,		(OFFSET_SEL | REGCLRSETALL)},
	{333,	0xffff0000,	0xff8f,		(OFFSET_SEL | REGCLRSETALL)},
	{589,	0xffff0000,	0xff8f,		(OFFSET_SEL | REGCLRSETALL)},
	{845,	0xffff0000,	0xff8f,		(OFFSET_SEL | REGCLRSETALL)},
	{1062,	0xffffff00,	0xff,		(OFFSET_SEL | REG4G | REG2G | F_CLRSET)},
	{1318,	0xffffff00,	0xff,		(OFFSET_SEL | REG4G | REG2G | F_CLRSET)},
	{1574,	0xffffff00,	0xff,		(OFFSET_SEL | REG4G | REG2G | F_CLRSET)},
	{1062,	0xffffff00,	0xfb,		(OFFSET_SEL | REG8G | F_CLRSET)},
	{1318,	0xffffff00,	0xfb,		(OFFSET_SEL | REG8G | F_CLRSET)},
	{1574,	0xffffff00,	0xfb,		(OFFSET_SEL | REG8G | F_CLRSET)},
	{1028,	0xffffffff,	0x1000000,	(OFFSET_SEL | REGCLRSETALL)},
	{1284,	0xffffffff,	0x1000000,	(OFFSET_SEL | REGCLRSETALL)},
	{1540,	0xffffffff,	0x1000000,	(OFFSET_SEL | REGCLRSETALL)},
	{1848,	0x0,		0x3cf07f8,	(OFFSET_SEL | REGSETALL)},
	{1849,	0x0,		0x3f,		(OFFSET_SEL | REGSETALL)},
	{1850,	0x0,		0x1fffff,	(OFFSET_SEL | REGSETALL)},
	{1851,	0x0,		0x060000,	(OFFSET_SEL | REGSETALL)},
	{130,	0x0000ffff,	0xffff0000,	(OFFSET_SEL | REGCLRSETALL)},
	{386,	0x0000ffff,	0xffff0000,	(OFFSET_SEL | REGCLRSETALL)},
	{642,	0x0000ffff,	0xffff0000,	(OFFSET_SEL | REGCLRSETALL)},
	{898,	0x0000ffff,	0xffff0000,	(OFFSET_SEL | REGCLRSETALL)},
	{131,	0xfffffff0,	0xf,		(OFFSET_SEL | REGCLRSETALL)},
	{387,	0xfffffff0,	0xf,		(OFFSET_SEL | REGCLRSETALL)},
	{643,	0xfffffff0,	0xf,		(OFFSET_SEL | REGCLRSETALL)},
	{899,	0xfffffff0,	0xf,		(OFFSET_SEL | REGCLRSETALL)},
	{29,	0xc0ffffff,	0x10000000,	(OFFSET_SEL | REGCLRSETALL)},
	{285,	0xc0ffffff,	0x10000000,	(OFFSET_SEL | REGCLRSETALL)},
	{541,	0xc0ffffff,	0x10000000,	(OFFSET_SEL | REGCLRSETALL)},
	{797,	0xc0ffffff,	0x10000000,	(OFFSET_SEL | REGCLRSETALL)},
	{30,	0xffffffff,	0x00080000,	(OFFSET_SEL | REGCLRSETALL)},
	{286,	0xffffffff,	0x00080000,	(OFFSET_SEL | REGCLRSETALL)},
	{542,	0xffffffff,	0x00080000,	(OFFSET_SEL | REGCLRSETALL)},
	{798,	0xffffffff,	0x00080000,	(OFFSET_SEL | REGCLRSETALL)},
	{31,	0xffffffc0,	0x00000010,	(OFFSET_SEL | REGCLRSETALL)},
	{287,	0xffffffc0,	0x00000010,	(OFFSET_SEL | REGCLRSETALL)},
	{543,	0xffffffc0,	0x00000010,	(OFFSET_SEL | REGCLRSETALL)},
	{799,	0xffffffc0,	0x00000010,	(OFFSET_SEL | REGCLRSETALL)},
	{1071,	0xfffffff0,	0x00000008,	(OFFSET_SEL | REGCLRSETALL)},
	{1327,	0xfffffff0,	0x00000008,	(OFFSET_SEL | REGCLRSETALL)},
	{1583,	0xfffffff0,	0x00000008,	(OFFSET_SEL | REGCLRSETALL)},
	{1808,	0xfffffff0,	0x00000008,	(OFFSET_SEL | REGCLRSETALL)},
	{1896,	0xfff0ffff,	0x00080000,	(OFFSET_SEL | REGCLRSETALL)},
};

void ddr_reg_set(u32 *reg, const struct ddr_reg_cfg *data,
		 u32 len, u32 mask)
{
	u32 *addr;
	u32 i;

	for (i = 0; i < len; i++) {
		if (!(data[i].flag & mask))
			continue;

		if (data[i].flag & OFFSET_SEL)
			addr = reg + PHY_AC_BASE_ADDR + data[i].offset;
		else
			addr = reg + PHY_BASE_ADDR + data[i].offset;

		if (data[i].flag & F_CLRSET)
			DDR_REG_TRIGGER(addr, data[i].mask, data[i].val);
		else if (data[i].flag & F_SET)
			out_le32(addr, data[i].val);
		else
			out_le32(addr, in_le32(addr) + data[i].val);
	}
}

void ddr_phy_start(u32 *phyreg, enum ddr_size_t size)
{
	u32 len;
	u32 mask;

	switch (size) {
	case DDR_SIZE_2G:
		mask = REG2G;
		break;

	case DDR_SIZE_4G:
		mask = REG4G;
		break;

	case DDR_SIZE_8G:
		mask = REG8G;
		break;

	case DDR_SIZE_16G:
	default:
		return;
	};

	len = ARRAY_SIZE(ddr_start_cfg);
	ddr_reg_set(phyreg, ddr_start_cfg, len, mask);
	out_le32(phyreg, 0x01);
}
