1 /*
2  * Copyright (C) 2011-2015 Panasonic Corporation
3  * Copyright (C) 2016      Socionext Inc.
4  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5  *
6  * SPDX-License-Identifier:	GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <linux/errno.h>
11 #include <linux/io.h>
12 #include <linux/sizes.h>
13 
14 #include "sg-regs.h"
15 #include "init.h"
16 
17 static int __uniphier_memconf_init(const struct uniphier_board_data *bd,
18 				   int have_ch2, int have_ch2_disable_bit)
19 {
20 	u32 val = 0;
21 	unsigned long size_per_word;
22 
23 	/* set up ch0 */
24 	switch (bd->dram_ch[0].width) {
25 	case 16:
26 		val |= SG_MEMCONF_CH0_NUM_1;
27 		size_per_word = bd->dram_ch[0].size;
28 		break;
29 	case 32:
30 		val |= SG_MEMCONF_CH0_NUM_2;
31 		size_per_word = bd->dram_ch[0].size >> 1;
32 		break;
33 	default:
34 		pr_err("error: unsupported DRAM ch0 width\n");
35 		return -EINVAL;
36 	}
37 
38 	switch (size_per_word) {
39 	case SZ_64M:
40 		val |= SG_MEMCONF_CH0_SZ_64M;
41 		break;
42 	case SZ_128M:
43 		val |= SG_MEMCONF_CH0_SZ_128M;
44 		break;
45 	case SZ_256M:
46 		val |= SG_MEMCONF_CH0_SZ_256M;
47 		break;
48 	case SZ_512M:
49 		val |= SG_MEMCONF_CH0_SZ_512M;
50 		break;
51 	case SZ_1G:
52 		val |= SG_MEMCONF_CH0_SZ_1G;
53 		break;
54 	default:
55 		pr_err("error: unsupported DRAM ch0 size\n");
56 		return -EINVAL;
57 	}
58 
59 	/* set up ch1 */
60 	switch (bd->dram_ch[1].width) {
61 	case 16:
62 		val |= SG_MEMCONF_CH1_NUM_1;
63 		size_per_word = bd->dram_ch[1].size;
64 		break;
65 	case 32:
66 		val |= SG_MEMCONF_CH1_NUM_2;
67 		size_per_word = bd->dram_ch[1].size >> 1;
68 		break;
69 	default:
70 		pr_err("error: unsupported DRAM ch1 width\n");
71 		return -EINVAL;
72 	}
73 
74 	switch (size_per_word) {
75 	case SZ_64M:
76 		val |= SG_MEMCONF_CH1_SZ_64M;
77 		break;
78 	case SZ_128M:
79 		val |= SG_MEMCONF_CH1_SZ_128M;
80 		break;
81 	case SZ_256M:
82 		val |= SG_MEMCONF_CH1_SZ_256M;
83 		break;
84 	case SZ_512M:
85 		val |= SG_MEMCONF_CH1_SZ_512M;
86 		break;
87 	case SZ_1G:
88 		val |= SG_MEMCONF_CH1_SZ_1G;
89 		break;
90 	default:
91 		pr_err("error: unsupported DRAM ch1 size\n");
92 		return -EINVAL;
93 	}
94 
95 	/* is sparse mem? */
96 	if (bd->dram_ch[0].base + bd->dram_ch[0].size < bd->dram_ch[1].base)
97 		val |= SG_MEMCONF_SPARSEMEM;
98 
99 	if (!have_ch2)
100 		goto out;
101 
102 	if (!bd->dram_ch[2].size) {
103 		if (have_ch2_disable_bit)
104 			val |= SG_MEMCONF_CH2_DISABLE;
105 		goto out;
106 	}
107 
108 	/* set up ch2 */
109 	switch (bd->dram_ch[2].width) {
110 	case 16:
111 		val |= SG_MEMCONF_CH2_NUM_1;
112 		size_per_word = bd->dram_ch[2].size;
113 		break;
114 	case 32:
115 		val |= SG_MEMCONF_CH2_NUM_2;
116 		size_per_word = bd->dram_ch[2].size >> 1;
117 		break;
118 	default:
119 		pr_err("error: unsupported DRAM ch2 width\n");
120 		return -EINVAL;
121 	}
122 
123 	switch (size_per_word) {
124 	case SZ_64M:
125 		val |= SG_MEMCONF_CH2_SZ_64M;
126 		break;
127 	case SZ_128M:
128 		val |= SG_MEMCONF_CH2_SZ_128M;
129 		break;
130 	case SZ_256M:
131 		val |= SG_MEMCONF_CH2_SZ_256M;
132 		break;
133 	case SZ_512M:
134 		val |= SG_MEMCONF_CH2_SZ_512M;
135 		break;
136 	case SZ_1G:
137 		val |= SG_MEMCONF_CH2_SZ_1G;
138 		break;
139 	default:
140 		pr_err("error: unsupported DRAM ch2 size\n");
141 		return -EINVAL;
142 	}
143 
144 out:
145 	writel(val, SG_MEMCONF);
146 
147 	return 0;
148 }
149 
150 int uniphier_memconf_2ch_init(const struct uniphier_board_data *bd)
151 {
152 	return __uniphier_memconf_init(bd, 0, 0);
153 }
154 
155 int uniphier_memconf_3ch_no_disbit_init(const struct uniphier_board_data *bd)
156 {
157 	return __uniphier_memconf_init(bd, 1, 0);
158 }
159 
160 int uniphier_memconf_3ch_init(const struct uniphier_board_data *bd)
161 {
162 	return __uniphier_memconf_init(bd, 1, 1);
163 }
164