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