blob: 2188b38d84b4a098c96e449bdd96d45400d30f26 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass70997d82017-04-05 16:23:36 -06002/*
3 * (C) Copyright 2012 Stephen Warren
Simon Glass70997d82017-04-05 16:23:36 -06004 */
5
6#include <common.h>
7#include <memalign.h>
Simon Glass2e4170b2017-04-05 16:23:40 -06008#include <phys2bus.h>
Simon Glass70997d82017-04-05 16:23:36 -06009#include <asm/arch/mbox.h>
Nicolas Saenz Julienned774da02020-06-29 18:37:22 +020010#include <linux/delay.h>
Simon Glass70997d82017-04-05 16:23:36 -060011
12struct msg_set_power_state {
13 struct bcm2835_mbox_hdr hdr;
14 struct bcm2835_mbox_tag_set_power_state set_power_state;
15 u32 end_tag;
16};
17
Simon Glassc6606512017-04-05 16:23:37 -060018struct msg_get_clock_rate {
19 struct bcm2835_mbox_hdr hdr;
20 struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
21 u32 end_tag;
22};
23
Vincent Fazio85bdd282021-09-14 13:19:19 -050024struct msg_set_sdhost_clock {
25 struct bcm2835_mbox_hdr hdr;
26 struct bcm2835_mbox_tag_set_sdhost_clock set_sdhost_clock;
27 u32 end_tag;
28};
29
Simon Glass2e4170b2017-04-05 16:23:40 -060030struct msg_query {
31 struct bcm2835_mbox_hdr hdr;
32 struct bcm2835_mbox_tag_physical_w_h physical_w_h;
33 u32 end_tag;
34};
35
Simon Glass7cac2fc2017-04-05 16:23:41 -060036struct msg_setup {
37 struct bcm2835_mbox_hdr hdr;
38 struct bcm2835_mbox_tag_physical_w_h physical_w_h;
39 struct bcm2835_mbox_tag_virtual_w_h virtual_w_h;
40 struct bcm2835_mbox_tag_depth depth;
41 struct bcm2835_mbox_tag_pixel_order pixel_order;
42 struct bcm2835_mbox_tag_alpha_mode alpha_mode;
43 struct bcm2835_mbox_tag_virtual_offset virtual_offset;
44 struct bcm2835_mbox_tag_overscan overscan;
45 struct bcm2835_mbox_tag_allocate_buffer allocate_buffer;
46 struct bcm2835_mbox_tag_pitch pitch;
47 u32 end_tag;
48};
49
Nicolas Saenz Julienned774da02020-06-29 18:37:22 +020050struct msg_notify_vl805_reset {
51 struct bcm2835_mbox_hdr hdr;
52 struct bcm2835_mbox_tag_pci_dev_addr dev_addr;
53 u32 end_tag;
54};
55
Simon Glass70997d82017-04-05 16:23:36 -060056int bcm2835_power_on_module(u32 module)
57{
58 ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1);
59 int ret;
60
61 BCM2835_MBOX_INIT_HDR(msg_pwr);
62 BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state,
63 SET_POWER_STATE);
64 msg_pwr->set_power_state.body.req.device_id = module;
65 msg_pwr->set_power_state.body.req.state =
66 BCM2835_MBOX_SET_POWER_STATE_REQ_ON |
67 BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT;
68
69 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
70 &msg_pwr->hdr);
71 if (ret) {
72 printf("bcm2835: Could not set module %u power state\n",
73 module);
74 return -EIO;
75 }
76
77 return 0;
78}
Simon Glassc6606512017-04-05 16:23:37 -060079
Jonathan Gray8ae1f822018-03-17 16:15:48 +110080int bcm2835_get_mmc_clock(u32 clock_id)
Simon Glassc6606512017-04-05 16:23:37 -060081{
82 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1);
83 int ret;
Vincent Fazio0a36afa2021-09-14 13:19:18 -050084 u32 clock_rate = 0;
Simon Glassc6606512017-04-05 16:23:37 -060085
86 ret = bcm2835_power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI);
87 if (ret)
88 return ret;
89
90 BCM2835_MBOX_INIT_HDR(msg_clk);
91 BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE);
Jonathan Gray8ae1f822018-03-17 16:15:48 +110092 msg_clk->get_clock_rate.body.req.clock_id = clock_id;
Simon Glassc6606512017-04-05 16:23:37 -060093
94 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr);
95 if (ret) {
96 printf("bcm2835: Could not query eMMC clock rate\n");
97 return -EIO;
98 }
99
Vincent Fazio0a36afa2021-09-14 13:19:18 -0500100 clock_rate = msg_clk->get_clock_rate.body.resp.rate_hz;
101
102 if (clock_rate == 0) {
103 BCM2835_MBOX_INIT_HDR(msg_clk);
104 BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_MAX_CLOCK_RATE);
105 msg_clk->get_clock_rate.body.req.clock_id = clock_id;
106
107 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr);
108 if (ret) {
109 printf("bcm2835: Could not query max eMMC clock rate\n");
110 return -EIO;
111 }
112
113 clock_rate = msg_clk->get_clock_rate.body.resp.rate_hz;
114 }
115
116 return clock_rate;
Simon Glassc6606512017-04-05 16:23:37 -0600117}
Simon Glass2e4170b2017-04-05 16:23:40 -0600118
Vincent Fazio85bdd282021-09-14 13:19:19 -0500119int bcm2835_set_sdhost_clock(u32 rate_hz, u32 *rate_1, u32 *rate_2)
120{
121 ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_sdhost_clock, msg_sdhost_clk, 1);
122 int ret;
123
124 BCM2835_MBOX_INIT_HDR(msg_sdhost_clk);
125 BCM2835_MBOX_INIT_TAG(&msg_sdhost_clk->set_sdhost_clock, SET_SDHOST_CLOCK);
126
127 msg_sdhost_clk->set_sdhost_clock.body.req.rate_hz = rate_hz;
128
129 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_sdhost_clk->hdr);
130 if (ret) {
131 printf("bcm2835: Could not query sdhost clock rate\n");
132 return -EIO;
133 }
134
135 *rate_1 = msg_sdhost_clk->set_sdhost_clock.body.resp.rate_1;
136 *rate_2 = msg_sdhost_clk->set_sdhost_clock.body.resp.rate_2;
137
138 return 0;
139}
140
Simon Glass2e4170b2017-04-05 16:23:40 -0600141int bcm2835_get_video_size(int *widthp, int *heightp)
142{
143 ALLOC_CACHE_ALIGN_BUFFER(struct msg_query, msg_query, 1);
144 int ret;
145
146 BCM2835_MBOX_INIT_HDR(msg_query);
147 BCM2835_MBOX_INIT_TAG_NO_REQ(&msg_query->physical_w_h,
148 GET_PHYSICAL_W_H);
149 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_query->hdr);
150 if (ret) {
151 printf("bcm2835: Could not query display resolution\n");
152 return ret;
153 }
154 *widthp = msg_query->physical_w_h.body.resp.width;
155 *heightp = msg_query->physical_w_h.body.resp.height;
156
157 return 0;
158}
Simon Glass7cac2fc2017-04-05 16:23:41 -0600159
160int bcm2835_set_video_params(int *widthp, int *heightp, int depth_bpp,
161 int pixel_order, int alpha_mode, ulong *fb_basep,
162 ulong *fb_sizep, int *pitchp)
163{
164 ALLOC_CACHE_ALIGN_BUFFER(struct msg_setup, msg_setup, 1);
165 int ret;
166
167 BCM2835_MBOX_INIT_HDR(msg_setup);
168 BCM2835_MBOX_INIT_TAG(&msg_setup->physical_w_h, SET_PHYSICAL_W_H);
169 msg_setup->physical_w_h.body.req.width = *widthp;
170 msg_setup->physical_w_h.body.req.height = *heightp;
171 BCM2835_MBOX_INIT_TAG(&msg_setup->virtual_w_h, SET_VIRTUAL_W_H);
172 msg_setup->virtual_w_h.body.req.width = *widthp;
173 msg_setup->virtual_w_h.body.req.height = *heightp;
174 BCM2835_MBOX_INIT_TAG(&msg_setup->depth, SET_DEPTH);
175 msg_setup->depth.body.req.bpp = 32;
176 BCM2835_MBOX_INIT_TAG(&msg_setup->pixel_order, SET_PIXEL_ORDER);
177 msg_setup->pixel_order.body.req.order = pixel_order;
178 BCM2835_MBOX_INIT_TAG(&msg_setup->alpha_mode, SET_ALPHA_MODE);
179 msg_setup->alpha_mode.body.req.alpha = alpha_mode;
180 BCM2835_MBOX_INIT_TAG(&msg_setup->virtual_offset, SET_VIRTUAL_OFFSET);
181 msg_setup->virtual_offset.body.req.x = 0;
182 msg_setup->virtual_offset.body.req.y = 0;
183 BCM2835_MBOX_INIT_TAG(&msg_setup->overscan, SET_OVERSCAN);
184 msg_setup->overscan.body.req.top = 0;
185 msg_setup->overscan.body.req.bottom = 0;
186 msg_setup->overscan.body.req.left = 0;
187 msg_setup->overscan.body.req.right = 0;
188 BCM2835_MBOX_INIT_TAG(&msg_setup->allocate_buffer, ALLOCATE_BUFFER);
189 msg_setup->allocate_buffer.body.req.alignment = 0x100;
190 BCM2835_MBOX_INIT_TAG_NO_REQ(&msg_setup->pitch, GET_PITCH);
191
192 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_setup->hdr);
193 if (ret) {
194 printf("bcm2835: Could not configure display\n");
195 return ret;
196 }
197 *widthp = msg_setup->physical_w_h.body.resp.width;
198 *heightp = msg_setup->physical_w_h.body.resp.height;
199 *pitchp = msg_setup->pitch.body.resp.pitch;
200 *fb_basep = bus_to_phys(
201 msg_setup->allocate_buffer.body.resp.fb_address);
202 *fb_sizep = msg_setup->allocate_buffer.body.resp.fb_size;
203
204 return 0;
205}
Nicolas Saenz Julienned774da02020-06-29 18:37:22 +0200206
207/*
208 * On the Raspberry Pi 4, after a PCI reset, VL805's (the xHCI chip) firmware
209 * may either be loaded directly from an EEPROM or, if not present, by the
210 * SoC's VideoCore. This informs VideoCore that VL805 needs its firmware
211 * loaded.
212 */
213int bcm2711_notify_vl805_reset(void)
214{
215 ALLOC_CACHE_ALIGN_BUFFER(struct msg_notify_vl805_reset,
216 msg_notify_vl805_reset, 1);
217 int ret;
Marek Szyprowski33166052021-09-17 10:19:43 +0200218 static int done = false;
219
220 if (done)
221 return 0;
222
223 done = true;
Nicolas Saenz Julienned774da02020-06-29 18:37:22 +0200224
225 BCM2835_MBOX_INIT_HDR(msg_notify_vl805_reset);
226 BCM2835_MBOX_INIT_TAG(&msg_notify_vl805_reset->dev_addr,
227 NOTIFY_XHCI_RESET);
228
229 /*
230 * The pci device address is expected like this:
231 *
232 * PCI_BUS << 20 | PCI_SLOT << 15 | PCI_FUNC << 12
233 *
234 * But since RPi4's PCIe setup is hardwired, we know the address in
235 * advance.
236 */
237 msg_notify_vl805_reset->dev_addr.body.req.dev_addr = 0x100000;
238
239 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
240 &msg_notify_vl805_reset->hdr);
241 if (ret) {
Vagrant Cascadian11872972021-12-21 13:06:52 -0800242 printf("bcm2711: Failed to load vl805's firmware, %d\n", ret);
Nicolas Saenz Julienned774da02020-06-29 18:37:22 +0200243 return -EIO;
244 }
245
246 udelay(200);
247
248 return 0;
249}