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