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)
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->flags & UNIPHIER_BD_DRAM_SPARSE)
97 		val |= SG_MEMCONF_SPARSEMEM;
98 
99 	if (!have_ch2)
100 		goto out;
101 
102 	if (!bd->dram_ch[2].size) {
103 		val |= SG_MEMCONF_CH2_DISABLE;
104 		goto out;
105 	}
106 
107 	/* set up ch2 */
108 	switch (bd->dram_ch[2].width) {
109 	case 16:
110 		val |= SG_MEMCONF_CH2_NUM_1;
111 		size_per_word = bd->dram_ch[2].size;
112 		break;
113 	case 32:
114 		val |= SG_MEMCONF_CH2_NUM_2;
115 		size_per_word = bd->dram_ch[2].size >> 1;
116 		break;
117 	default:
118 		pr_err("error: unsupported DRAM ch2 width\n");
119 		return -EINVAL;
120 	}
121 
122 	switch (size_per_word) {
123 	case SZ_64M:
124 		val |= SG_MEMCONF_CH2_SZ_64M;
125 		break;
126 	case SZ_128M:
127 		val |= SG_MEMCONF_CH2_SZ_128M;
128 		break;
129 	case SZ_256M:
130 		val |= SG_MEMCONF_CH2_SZ_256M;
131 		break;
132 	case SZ_512M:
133 		val |= SG_MEMCONF_CH2_SZ_512M;
134 		break;
135 	case SZ_1G:
136 		val |= SG_MEMCONF_CH2_SZ_1G;
137 		break;
138 	default:
139 		pr_err("error: unsupported DRAM ch2 size\n");
140 		return -EINVAL;
141 	}
142 
143 out:
144 	writel(val, SG_MEMCONF);
145 
146 	return 0;
147 }
148 
149 int uniphier_memconf_2ch_init(const struct uniphier_board_data *bd)
150 {
151 	return __uniphier_memconf_init(bd, 0);
152 }
153 
154 int uniphier_memconf_3ch_init(const struct uniphier_board_data *bd)
155 {
156 	return __uniphier_memconf_init(bd, 1);
157 }
158