1/*
2 * Copyright 2011, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Alexander von Gluck IV, kallisti5@unixzen.com
7 */
8
9
10#include "bios.h"
11
12#include <Debug.h>
13
14#include "accelerant.h"
15#include "accelerant_protos.h"
16
17
18#undef TRACE
19
20#define TRACE_ATOM
21#ifdef TRACE_ATOM
22#   define TRACE(x...) _sPrintf("radeon_hd: " x)
23#else
24#   define TRACE(x...) ;
25#endif
26
27
28atom_context* gAtomContext;
29
30
31void
32radeon_bios_init_scratch()
33{
34	radeon_shared_info &info = *gInfo->shared_info;
35
36	uint32 biosScratch2;
37	uint32 biosScratch6;
38
39	if (info.chipsetID >= RADEON_R600) {
40		biosScratch2 = Read32(OUT, R600_SCRATCH_REG2);
41		biosScratch6 = Read32(OUT, R600_SCRATCH_REG6);
42	} else {
43		biosScratch2 = Read32(OUT, RADEON_BIOS_2_SCRATCH);
44		biosScratch6 = Read32(OUT, RADEON_BIOS_6_SCRATCH);
45	}
46
47	biosScratch2 |= ATOM_S2_VRI_BRIGHT_ENABLE;
48		// bios should not control backlight
49	biosScratch6 |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
50		// bios shouldn't handle mode switching
51
52	if (info.chipsetID >= RADEON_R600) {
53		Write32(OUT, R600_SCRATCH_REG2, biosScratch2);
54		Write32(OUT, R600_SCRATCH_REG6, biosScratch6);
55	} else {
56		Write32(OUT, RADEON_BIOS_2_SCRATCH, biosScratch2);
57		Write32(OUT, RADEON_BIOS_6_SCRATCH, biosScratch6);
58	}
59}
60
61
62bool
63radeon_bios_isposted()
64{
65	// aka, is primary graphics card that POST loaded
66
67	radeon_shared_info &info = *gInfo->shared_info;
68	uint32 reg;
69
70	if (info.chipsetID == RADEON_PALM) {
71		// palms
72		reg = Read32(OUT, EVERGREEN_CRTC_CONTROL
73			+ EVERGREEN_CRTC0_REGISTER_OFFSET)
74			| Read32(OUT, EVERGREEN_CRTC_CONTROL
75			+ EVERGREEN_CRTC1_REGISTER_OFFSET);
76		if ((reg & EVERGREEN_CRTC_MASTER_EN) != 0)
77			return true;
78	} else if (info.chipsetID >= RADEON_CEDAR) {
79		// evergreen or higher
80		reg = Read32(OUT, EVERGREEN_CRTC_CONTROL
81				+ EVERGREEN_CRTC0_REGISTER_OFFSET)
82			| Read32(OUT, EVERGREEN_CRTC_CONTROL
83				+ EVERGREEN_CRTC1_REGISTER_OFFSET)
84			| Read32(OUT, EVERGREEN_CRTC_CONTROL
85				+ EVERGREEN_CRTC2_REGISTER_OFFSET)
86			| Read32(OUT, EVERGREEN_CRTC_CONTROL
87				+ EVERGREEN_CRTC3_REGISTER_OFFSET)
88			| Read32(OUT, EVERGREEN_CRTC_CONTROL
89				+ EVERGREEN_CRTC4_REGISTER_OFFSET)
90			| Read32(OUT, EVERGREEN_CRTC_CONTROL
91				+ EVERGREEN_CRTC5_REGISTER_OFFSET);
92		if ((reg & EVERGREEN_CRTC_MASTER_EN) != 0)
93			return true;
94	} else if (info.chipsetID >= RADEON_RS600) {
95		// avivio through r700
96		reg = Read32(OUT, AVIVO_D1CRTC_CONTROL)
97			| Read32(OUT, AVIVO_D2CRTC_CONTROL);
98		if ((reg & AVIVO_CRTC_EN) != 0) {
99			return true;
100		}
101	} else {
102		// early cards
103		reg = Read32(OUT, RADEON_CRTC_GEN_CNTL)
104			| Read32(OUT, RADEON_CRTC2_GEN_CNTL);
105		if ((reg & RADEON_CRTC_EN) != 0)
106			return true;
107	}
108
109	// also check memory size incase crt controlers are disabled
110	if (info.chipsetID >= RADEON_R600)
111		reg = Read32(OUT, R600_CONFIG_MEMSIZE);
112	else
113		reg = Read32(OUT, RADEON_CONFIG_MEMSIZE);
114
115	if (reg)
116		return true;
117
118	return false;
119}
120
121
122status_t
123radeon_init_bios(uint8* bios)
124{
125	radeon_shared_info &info = *gInfo->shared_info;
126
127	if (info.has_rom == false) {
128		TRACE("%s: called even though has_rom == false\n", __func__);
129		return B_ERROR;
130	}
131
132	#ifdef TRACE_ATOM
133	radeon_dump_bios();
134	#endif
135
136	struct card_info* atom_card_info
137		= (card_info*)malloc(sizeof(card_info));
138
139	if (!atom_card_info)
140		return B_NO_MEMORY;
141
142	atom_card_info->reg_read = Read32Cail;
143	atom_card_info->reg_write = Write32Cail;
144
145	// use MMIO instead of PCI I/O BAR
146	atom_card_info->ioreg_read = Read32Cail;
147	atom_card_info->ioreg_write = Write32Cail;
148
149	atom_card_info->mc_read = _read32;
150	atom_card_info->mc_write = _write32;
151	atom_card_info->pll_read = _read32;
152	atom_card_info->pll_write = _write32;
153
154	// Point AtomBIOS parser to card bios and malloc gAtomContext
155	gAtomContext = atom_parse(atom_card_info, bios);
156
157	if (gAtomContext == NULL) {
158		TRACE("%s: couldn't parse system AtomBIOS\n", __func__);
159		return B_ERROR;
160	}
161
162	if ((gAtomContext->exec_sem = create_sem(1, "AtomBIOS_exec"))
163		< B_NO_ERROR) {
164		TRACE("%s: couldn't create semaphore for AtomBIOS exec thread!\n",
165			__func__);
166		return B_ERROR;
167	}
168
169	radeon_bios_init_scratch();
170	atom_allocate_fb_scratch(gAtomContext);
171
172	// post card atombios if needed
173	if (radeon_bios_isposted() == false) {
174		TRACE("%s: init AtomBIOS for this card as it is not not posted\n",
175			__func__);
176		// radeon_gpu_reset();	// <= r500 only?
177		atom_asic_init(gAtomContext);
178	} else {
179		TRACE("%s: AtomBIOS is already posted\n",
180			__func__);
181	}
182
183	return B_OK;
184}
185
186
187status_t
188radeon_dump_bios()
189{
190	// For debugging use, dump card AtomBIOS
191	radeon_shared_info &info = *gInfo->shared_info;
192
193	TRACE("%s: Dumping AtomBIOS as ATOM_DEBUG is set...\n",
194		__func__);
195
196	FILE* fp;
197	char filename[255];
198	sprintf(filename, "/boot/system/cache/tmp/radeon_hd_bios_1002_%" B_PRIx32
199		"_%" B_PRIu32 ".bin", info.pciID, info.deviceIndex);
200
201	fp = fopen(filename, "wb");
202	if (fp == NULL) {
203		TRACE("%s: Cannot create AtomBIOS blob at %s\n", __func__, filename);
204		return B_ERROR;
205	}
206
207	fwrite(gInfo->rom, info.rom_size, 1, fp);
208
209	fclose(fp);
210
211	TRACE("%s: AtomBIOS dumped to %s\n", __func__, filename);
212
213	return B_OK;
214}
215