xref: /dflybsd-src/sys/dev/drm/radeon/rv770_smc.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
157e252bfSMichael Neumann /*
257e252bfSMichael Neumann  * Copyright 2011 Advanced Micro Devices, Inc.
357e252bfSMichael Neumann  *
457e252bfSMichael Neumann  * Permission is hereby granted, free of charge, to any person obtaining a
557e252bfSMichael Neumann  * copy of this software and associated documentation files (the "Software"),
657e252bfSMichael Neumann  * to deal in the Software without restriction, including without limitation
757e252bfSMichael Neumann  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
857e252bfSMichael Neumann  * and/or sell copies of the Software, and to permit persons to whom the
957e252bfSMichael Neumann  * Software is furnished to do so, subject to the following conditions:
1057e252bfSMichael Neumann  *
1157e252bfSMichael Neumann  * The above copyright notice and this permission notice shall be included in
1257e252bfSMichael Neumann  * all copies or substantial portions of the Software.
1357e252bfSMichael Neumann  *
1457e252bfSMichael Neumann  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1557e252bfSMichael Neumann  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1657e252bfSMichael Neumann  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1757e252bfSMichael Neumann  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1857e252bfSMichael Neumann  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1957e252bfSMichael Neumann  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2057e252bfSMichael Neumann  * OTHER DEALINGS IN THE SOFTWARE.
2157e252bfSMichael Neumann  *
2257e252bfSMichael Neumann  * Authors: Alex Deucher
2357e252bfSMichael Neumann  */
2457e252bfSMichael Neumann 
2557e252bfSMichael Neumann #include <linux/firmware.h>
26*3f2dd94aSFrançois Tigeot #include <drm/drmP.h>
2757e252bfSMichael Neumann #include "radeon.h"
2857e252bfSMichael Neumann #include "rv770d.h"
2957e252bfSMichael Neumann #include "rv770_dpm.h"
3057e252bfSMichael Neumann #include "rv770_smc.h"
3157e252bfSMichael Neumann #include "atom.h"
3257e252bfSMichael Neumann #include "radeon_ucode.h"
3357e252bfSMichael Neumann 
3457e252bfSMichael Neumann #define FIRST_SMC_INT_VECT_REG 0xFFD8
3557e252bfSMichael Neumann #define FIRST_INT_VECT_S19     0xFFC0
3657e252bfSMichael Neumann 
3757e252bfSMichael Neumann static const u8 rv770_smc_int_vectors[] =
3857e252bfSMichael Neumann {
3957e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4057e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4157e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4257e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4357e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4457e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4557e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4657e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4757e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4857e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
4957e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
5057e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
5157e252bfSMichael Neumann 	0x08, 0x10, 0x0C, 0xD7,
5257e252bfSMichael Neumann 	0x08, 0x2B, 0x08, 0x10,
5357e252bfSMichael Neumann 	0x03, 0x51, 0x03, 0x51,
5457e252bfSMichael Neumann 	0x03, 0x51, 0x03, 0x51
5557e252bfSMichael Neumann };
5657e252bfSMichael Neumann 
5757e252bfSMichael Neumann static const u8 rv730_smc_int_vectors[] =
5857e252bfSMichael Neumann {
5957e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6057e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6157e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6257e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6357e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6457e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6557e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6657e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6757e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6857e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
6957e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
7057e252bfSMichael Neumann 	0x08, 0x15, 0x08, 0x15,
7157e252bfSMichael Neumann 	0x08, 0x15, 0x0C, 0xBB,
7257e252bfSMichael Neumann 	0x08, 0x30, 0x08, 0x15,
7357e252bfSMichael Neumann 	0x03, 0x56, 0x03, 0x56,
7457e252bfSMichael Neumann 	0x03, 0x56, 0x03, 0x56
7557e252bfSMichael Neumann };
7657e252bfSMichael Neumann 
7757e252bfSMichael Neumann static const u8 rv710_smc_int_vectors[] =
7857e252bfSMichael Neumann {
7957e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8057e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8157e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8257e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8357e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8457e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8557e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8657e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8757e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8857e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
8957e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
9057e252bfSMichael Neumann 	0x08, 0x04, 0x08, 0x04,
9157e252bfSMichael Neumann 	0x08, 0x04, 0x0C, 0xCB,
9257e252bfSMichael Neumann 	0x08, 0x1F, 0x08, 0x04,
9357e252bfSMichael Neumann 	0x03, 0x51, 0x03, 0x51,
9457e252bfSMichael Neumann 	0x03, 0x51, 0x03, 0x51
9557e252bfSMichael Neumann };
9657e252bfSMichael Neumann 
9757e252bfSMichael Neumann static const u8 rv740_smc_int_vectors[] =
9857e252bfSMichael Neumann {
9957e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10057e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10157e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10257e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10357e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10457e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10557e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10657e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10757e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10857e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
10957e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
11057e252bfSMichael Neumann 	0x08, 0x10, 0x08, 0x10,
11157e252bfSMichael Neumann 	0x08, 0x10, 0x0C, 0xD7,
11257e252bfSMichael Neumann 	0x08, 0x2B, 0x08, 0x10,
11357e252bfSMichael Neumann 	0x03, 0x51, 0x03, 0x51,
11457e252bfSMichael Neumann 	0x03, 0x51, 0x03, 0x51
11557e252bfSMichael Neumann };
11657e252bfSMichael Neumann 
11757e252bfSMichael Neumann static const u8 cedar_smc_int_vectors[] =
11857e252bfSMichael Neumann {
11957e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12057e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12157e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12257e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12357e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12457e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12557e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12657e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12757e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12857e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
12957e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
13057e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
13157e252bfSMichael Neumann 	0x0B, 0x05, 0x11, 0x8B,
13257e252bfSMichael Neumann 	0x0B, 0x20, 0x0B, 0x05,
13357e252bfSMichael Neumann 	0x04, 0xF6, 0x04, 0xF6,
13457e252bfSMichael Neumann 	0x04, 0xF6, 0x04, 0xF6
13557e252bfSMichael Neumann };
13657e252bfSMichael Neumann 
13757e252bfSMichael Neumann static const u8 redwood_smc_int_vectors[] =
13857e252bfSMichael Neumann {
13957e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14057e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14157e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14257e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14357e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14457e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14557e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14657e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14757e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14857e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
14957e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
15057e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
15157e252bfSMichael Neumann 	0x0B, 0x05, 0x11, 0x8B,
15257e252bfSMichael Neumann 	0x0B, 0x20, 0x0B, 0x05,
15357e252bfSMichael Neumann 	0x04, 0xF6, 0x04, 0xF6,
15457e252bfSMichael Neumann 	0x04, 0xF6, 0x04, 0xF6
15557e252bfSMichael Neumann };
15657e252bfSMichael Neumann 
15757e252bfSMichael Neumann static const u8 juniper_smc_int_vectors[] =
15857e252bfSMichael Neumann {
15957e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16057e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16157e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16257e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16357e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16457e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16557e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16657e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16757e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16857e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
16957e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
17057e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
17157e252bfSMichael Neumann 	0x0B, 0x05, 0x11, 0x8B,
17257e252bfSMichael Neumann 	0x0B, 0x20, 0x0B, 0x05,
17357e252bfSMichael Neumann 	0x04, 0xF6, 0x04, 0xF6,
17457e252bfSMichael Neumann 	0x04, 0xF6, 0x04, 0xF6
17557e252bfSMichael Neumann };
17657e252bfSMichael Neumann 
17757e252bfSMichael Neumann static const u8 cypress_smc_int_vectors[] =
17857e252bfSMichael Neumann {
17957e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18057e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18157e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18257e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18357e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18457e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18557e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18657e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18757e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18857e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
18957e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
19057e252bfSMichael Neumann 	0x0B, 0x05, 0x0B, 0x05,
19157e252bfSMichael Neumann 	0x0B, 0x05, 0x11, 0x8B,
19257e252bfSMichael Neumann 	0x0B, 0x20, 0x0B, 0x05,
19357e252bfSMichael Neumann 	0x04, 0xF6, 0x04, 0xF6,
19457e252bfSMichael Neumann 	0x04, 0xF6, 0x04, 0xF6
19557e252bfSMichael Neumann };
19657e252bfSMichael Neumann 
19757e252bfSMichael Neumann static const u8 barts_smc_int_vectors[] =
19857e252bfSMichael Neumann {
19957e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20057e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20157e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20257e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20357e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20457e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20557e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20657e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20757e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20857e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
20957e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
21057e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
21157e252bfSMichael Neumann 	0x0C, 0x14, 0x12, 0xAA,
21257e252bfSMichael Neumann 	0x0C, 0x2F, 0x15, 0xF6,
21357e252bfSMichael Neumann 	0x15, 0xF6, 0x05, 0x0A,
21457e252bfSMichael Neumann 	0x05, 0x0A, 0x05, 0x0A
21557e252bfSMichael Neumann };
21657e252bfSMichael Neumann 
21757e252bfSMichael Neumann static const u8 turks_smc_int_vectors[] =
21857e252bfSMichael Neumann {
21957e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22057e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22157e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22257e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22357e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22457e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22557e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22657e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22757e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22857e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
22957e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
23057e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
23157e252bfSMichael Neumann 	0x0C, 0x14, 0x12, 0xAA,
23257e252bfSMichael Neumann 	0x0C, 0x2F, 0x15, 0xF6,
23357e252bfSMichael Neumann 	0x15, 0xF6, 0x05, 0x0A,
23457e252bfSMichael Neumann 	0x05, 0x0A, 0x05, 0x0A
23557e252bfSMichael Neumann };
23657e252bfSMichael Neumann 
23757e252bfSMichael Neumann static const u8 caicos_smc_int_vectors[] =
23857e252bfSMichael Neumann {
23957e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24057e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24157e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24257e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24357e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24457e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24557e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24657e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24757e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24857e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
24957e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
25057e252bfSMichael Neumann 	0x0C, 0x14, 0x0C, 0x14,
25157e252bfSMichael Neumann 	0x0C, 0x14, 0x12, 0xAA,
25257e252bfSMichael Neumann 	0x0C, 0x2F, 0x15, 0xF6,
25357e252bfSMichael Neumann 	0x15, 0xF6, 0x05, 0x0A,
25457e252bfSMichael Neumann 	0x05, 0x0A, 0x05, 0x0A
25557e252bfSMichael Neumann };
25657e252bfSMichael Neumann 
25757e252bfSMichael Neumann static const u8 cayman_smc_int_vectors[] =
25857e252bfSMichael Neumann {
25957e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26057e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26157e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26257e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26357e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26457e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26557e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26657e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26757e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26857e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
26957e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
27057e252bfSMichael Neumann 	0x12, 0x05, 0x12, 0x05,
27157e252bfSMichael Neumann 	0x12, 0x05, 0x18, 0xEA,
27257e252bfSMichael Neumann 	0x12, 0x20, 0x1C, 0x34,
27357e252bfSMichael Neumann 	0x1C, 0x34, 0x08, 0x72,
27457e252bfSMichael Neumann 	0x08, 0x72, 0x08, 0x72
27557e252bfSMichael Neumann };
27657e252bfSMichael Neumann 
rv770_set_smc_sram_address(struct radeon_device * rdev,u16 smc_address,u16 limit)277c6f73aabSFrançois Tigeot static int rv770_set_smc_sram_address(struct radeon_device *rdev,
27857e252bfSMichael Neumann 				      u16 smc_address, u16 limit)
27957e252bfSMichael Neumann {
28057e252bfSMichael Neumann 	u32 addr;
28157e252bfSMichael Neumann 
28257e252bfSMichael Neumann 	if (smc_address & 3)
28357e252bfSMichael Neumann 		return -EINVAL;
28457e252bfSMichael Neumann 	if ((smc_address + 3) > limit)
28557e252bfSMichael Neumann 		return -EINVAL;
28657e252bfSMichael Neumann 
28757e252bfSMichael Neumann 	addr = smc_address;
28857e252bfSMichael Neumann 	addr |= SMC_SRAM_AUTO_INC_DIS;
28957e252bfSMichael Neumann 
29057e252bfSMichael Neumann 	WREG32(SMC_SRAM_ADDR, addr);
29157e252bfSMichael Neumann 
29257e252bfSMichael Neumann 	return 0;
29357e252bfSMichael Neumann }
29457e252bfSMichael Neumann 
rv770_copy_bytes_to_smc(struct radeon_device * rdev,u16 smc_start_address,const u8 * src,u16 byte_count,u16 limit)29557e252bfSMichael Neumann int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
29657e252bfSMichael Neumann 			    u16 smc_start_address, const u8 *src,
29757e252bfSMichael Neumann 			    u16 byte_count, u16 limit)
29857e252bfSMichael Neumann {
299a85cb24fSFrançois Tigeot 	unsigned long flags;
30057e252bfSMichael Neumann 	u32 data, original_data, extra_shift;
30157e252bfSMichael Neumann 	u16 addr;
302c6f73aabSFrançois Tigeot 	int ret = 0;
30357e252bfSMichael Neumann 
30457e252bfSMichael Neumann 	if (smc_start_address & 3)
30557e252bfSMichael Neumann 		return -EINVAL;
30657e252bfSMichael Neumann 	if ((smc_start_address + byte_count) > limit)
30757e252bfSMichael Neumann 		return -EINVAL;
30857e252bfSMichael Neumann 
30957e252bfSMichael Neumann 	addr = smc_start_address;
31057e252bfSMichael Neumann 
311a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
31257e252bfSMichael Neumann 	while (byte_count >= 4) {
31357e252bfSMichael Neumann 		/* SMC address space is BE */
31457e252bfSMichael Neumann 		data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
31557e252bfSMichael Neumann 
31657e252bfSMichael Neumann 		ret = rv770_set_smc_sram_address(rdev, addr, limit);
31757e252bfSMichael Neumann 		if (ret)
318c6f73aabSFrançois Tigeot 			goto done;
31957e252bfSMichael Neumann 
32057e252bfSMichael Neumann 		WREG32(SMC_SRAM_DATA, data);
32157e252bfSMichael Neumann 
32257e252bfSMichael Neumann 		src += 4;
32357e252bfSMichael Neumann 		byte_count -= 4;
32457e252bfSMichael Neumann 		addr += 4;
32557e252bfSMichael Neumann 	}
32657e252bfSMichael Neumann 
32757e252bfSMichael Neumann 	/* RMW for final bytes */
32857e252bfSMichael Neumann 	if (byte_count > 0) {
32957e252bfSMichael Neumann 		data = 0;
33057e252bfSMichael Neumann 
33157e252bfSMichael Neumann 		ret = rv770_set_smc_sram_address(rdev, addr, limit);
33257e252bfSMichael Neumann 		if (ret)
333c6f73aabSFrançois Tigeot 			goto done;
33457e252bfSMichael Neumann 
33557e252bfSMichael Neumann 		original_data = RREG32(SMC_SRAM_DATA);
33657e252bfSMichael Neumann 
33757e252bfSMichael Neumann 		extra_shift = 8 * (4 - byte_count);
33857e252bfSMichael Neumann 
33957e252bfSMichael Neumann 		while (byte_count > 0) {
34057e252bfSMichael Neumann 			/* SMC address space is BE */
34157e252bfSMichael Neumann 			data = (data << 8) + *src++;
34257e252bfSMichael Neumann 			byte_count--;
34357e252bfSMichael Neumann 		}
34457e252bfSMichael Neumann 
34557e252bfSMichael Neumann 		data <<= extra_shift;
34657e252bfSMichael Neumann 
34757e252bfSMichael Neumann 		data |= (original_data & ~((~0UL) << extra_shift));
34857e252bfSMichael Neumann 
34957e252bfSMichael Neumann 		ret = rv770_set_smc_sram_address(rdev, addr, limit);
35057e252bfSMichael Neumann 		if (ret)
351c6f73aabSFrançois Tigeot 			goto done;
35257e252bfSMichael Neumann 
35357e252bfSMichael Neumann 		WREG32(SMC_SRAM_DATA, data);
35457e252bfSMichael Neumann 	}
35557e252bfSMichael Neumann 
356c6f73aabSFrançois Tigeot done:
357a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
358c6f73aabSFrançois Tigeot 
359c6f73aabSFrançois Tigeot 	return ret;
36057e252bfSMichael Neumann }
36157e252bfSMichael Neumann 
rv770_program_interrupt_vectors(struct radeon_device * rdev,u32 smc_first_vector,const u8 * src,u32 byte_count)36257e252bfSMichael Neumann static int rv770_program_interrupt_vectors(struct radeon_device *rdev,
36357e252bfSMichael Neumann 					   u32 smc_first_vector, const u8 *src,
36457e252bfSMichael Neumann 					   u32 byte_count)
36557e252bfSMichael Neumann {
36657e252bfSMichael Neumann 	u32 tmp, i;
36757e252bfSMichael Neumann 
36857e252bfSMichael Neumann 	if (byte_count % 4)
36957e252bfSMichael Neumann 		return -EINVAL;
37057e252bfSMichael Neumann 
37157e252bfSMichael Neumann 	if (smc_first_vector < FIRST_SMC_INT_VECT_REG) {
37257e252bfSMichael Neumann 		tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector;
37357e252bfSMichael Neumann 
37457e252bfSMichael Neumann 		if (tmp > byte_count)
37557e252bfSMichael Neumann 			return 0;
37657e252bfSMichael Neumann 
37757e252bfSMichael Neumann 		byte_count -= tmp;
37857e252bfSMichael Neumann 		src += tmp;
37957e252bfSMichael Neumann 		smc_first_vector = FIRST_SMC_INT_VECT_REG;
38057e252bfSMichael Neumann 	}
38157e252bfSMichael Neumann 
38257e252bfSMichael Neumann 	for (i = 0; i < byte_count; i += 4) {
38357e252bfSMichael Neumann 		/* SMC address space is BE */
38457e252bfSMichael Neumann 		tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
38557e252bfSMichael Neumann 
38657e252bfSMichael Neumann 		WREG32(SMC_ISR_FFD8_FFDB + i, tmp);
38757e252bfSMichael Neumann 	}
38857e252bfSMichael Neumann 
38957e252bfSMichael Neumann 	return 0;
39057e252bfSMichael Neumann }
39157e252bfSMichael Neumann 
rv770_start_smc(struct radeon_device * rdev)39257e252bfSMichael Neumann void rv770_start_smc(struct radeon_device *rdev)
39357e252bfSMichael Neumann {
39457e252bfSMichael Neumann 	WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
39557e252bfSMichael Neumann }
39657e252bfSMichael Neumann 
rv770_reset_smc(struct radeon_device * rdev)39757e252bfSMichael Neumann void rv770_reset_smc(struct radeon_device *rdev)
39857e252bfSMichael Neumann {
39957e252bfSMichael Neumann 	WREG32_P(SMC_IO, 0, ~SMC_RST_N);
40057e252bfSMichael Neumann }
40157e252bfSMichael Neumann 
rv770_stop_smc_clock(struct radeon_device * rdev)40257e252bfSMichael Neumann void rv770_stop_smc_clock(struct radeon_device *rdev)
40357e252bfSMichael Neumann {
40457e252bfSMichael Neumann 	WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
40557e252bfSMichael Neumann }
40657e252bfSMichael Neumann 
rv770_start_smc_clock(struct radeon_device * rdev)40757e252bfSMichael Neumann void rv770_start_smc_clock(struct radeon_device *rdev)
40857e252bfSMichael Neumann {
40957e252bfSMichael Neumann 	WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
41057e252bfSMichael Neumann }
41157e252bfSMichael Neumann 
rv770_is_smc_running(struct radeon_device * rdev)41257e252bfSMichael Neumann bool rv770_is_smc_running(struct radeon_device *rdev)
41357e252bfSMichael Neumann {
41457e252bfSMichael Neumann 	u32 tmp;
41557e252bfSMichael Neumann 
41657e252bfSMichael Neumann 	tmp = RREG32(SMC_IO);
41757e252bfSMichael Neumann 
41857e252bfSMichael Neumann 	if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN))
41957e252bfSMichael Neumann 		return true;
42057e252bfSMichael Neumann 	else
42157e252bfSMichael Neumann 		return false;
42257e252bfSMichael Neumann }
42357e252bfSMichael Neumann 
rv770_send_msg_to_smc(struct radeon_device * rdev,PPSMC_Msg msg)42457e252bfSMichael Neumann PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
42557e252bfSMichael Neumann {
42657e252bfSMichael Neumann 	u32 tmp;
42757e252bfSMichael Neumann 	int i;
42857e252bfSMichael Neumann 	PPSMC_Result result;
42957e252bfSMichael Neumann 
43057e252bfSMichael Neumann 	if (!rv770_is_smc_running(rdev))
43157e252bfSMichael Neumann 		return PPSMC_Result_Failed;
43257e252bfSMichael Neumann 
43357e252bfSMichael Neumann 	WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK);
43457e252bfSMichael Neumann 
43557e252bfSMichael Neumann 	for (i = 0; i < rdev->usec_timeout; i++) {
43657e252bfSMichael Neumann 		tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
43757e252bfSMichael Neumann 		tmp >>= HOST_SMC_RESP_SHIFT;
43857e252bfSMichael Neumann 		if (tmp != 0)
43957e252bfSMichael Neumann 			break;
440c4ef309bSzrj 		udelay(1);
44157e252bfSMichael Neumann 	}
44257e252bfSMichael Neumann 
44357e252bfSMichael Neumann 	tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
44457e252bfSMichael Neumann 	tmp >>= HOST_SMC_RESP_SHIFT;
44557e252bfSMichael Neumann 
44657e252bfSMichael Neumann 	result = (PPSMC_Result)tmp;
44757e252bfSMichael Neumann 	return result;
44857e252bfSMichael Neumann }
44957e252bfSMichael Neumann 
rv770_wait_for_smc_inactive(struct radeon_device * rdev)45057e252bfSMichael Neumann PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev)
45157e252bfSMichael Neumann {
45257e252bfSMichael Neumann 	int i;
45357e252bfSMichael Neumann 	PPSMC_Result result = PPSMC_Result_OK;
45457e252bfSMichael Neumann 
45557e252bfSMichael Neumann 	if (!rv770_is_smc_running(rdev))
45657e252bfSMichael Neumann 		return result;
45757e252bfSMichael Neumann 
45857e252bfSMichael Neumann 	for (i = 0; i < rdev->usec_timeout; i++) {
45957e252bfSMichael Neumann 		if (RREG32(SMC_IO) & SMC_STOP_MODE)
46057e252bfSMichael Neumann 			break;
461c4ef309bSzrj 		udelay(1);
46257e252bfSMichael Neumann 	}
46357e252bfSMichael Neumann 
46457e252bfSMichael Neumann 	return result;
46557e252bfSMichael Neumann }
46657e252bfSMichael Neumann 
rv770_clear_smc_sram(struct radeon_device * rdev,u16 limit)46757e252bfSMichael Neumann static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit)
46857e252bfSMichael Neumann {
469a85cb24fSFrançois Tigeot 	unsigned long flags;
47057e252bfSMichael Neumann 	u16 i;
47157e252bfSMichael Neumann 
472a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
47357e252bfSMichael Neumann 	for (i = 0;  i < limit; i += 4) {
47457e252bfSMichael Neumann 		rv770_set_smc_sram_address(rdev, i, limit);
47557e252bfSMichael Neumann 		WREG32(SMC_SRAM_DATA, 0);
47657e252bfSMichael Neumann 	}
477a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
47857e252bfSMichael Neumann }
47957e252bfSMichael Neumann 
rv770_load_smc_ucode(struct radeon_device * rdev,u16 limit)48057e252bfSMichael Neumann int rv770_load_smc_ucode(struct radeon_device *rdev,
48157e252bfSMichael Neumann 			 u16 limit)
48257e252bfSMichael Neumann {
48357e252bfSMichael Neumann 	int ret;
48457e252bfSMichael Neumann 	const u8 *int_vect;
48557e252bfSMichael Neumann 	u16 int_vect_start_address;
48657e252bfSMichael Neumann 	u16 int_vect_size;
48757e252bfSMichael Neumann 	const u8 *ucode_data;
48857e252bfSMichael Neumann 	u16 ucode_start_address;
48957e252bfSMichael Neumann 	u16 ucode_size;
49057e252bfSMichael Neumann 
49157e252bfSMichael Neumann 	if (!rdev->smc_fw)
49257e252bfSMichael Neumann 		return -EINVAL;
49357e252bfSMichael Neumann 
49457e252bfSMichael Neumann 	rv770_clear_smc_sram(rdev, limit);
49557e252bfSMichael Neumann 
49657e252bfSMichael Neumann 	switch (rdev->family) {
49757e252bfSMichael Neumann 	case CHIP_RV770:
49857e252bfSMichael Neumann 		ucode_start_address = RV770_SMC_UCODE_START;
49957e252bfSMichael Neumann 		ucode_size = RV770_SMC_UCODE_SIZE;
50057e252bfSMichael Neumann 		int_vect = (const u8 *)&rv770_smc_int_vectors;
50157e252bfSMichael Neumann 		int_vect_start_address = RV770_SMC_INT_VECTOR_START;
50257e252bfSMichael Neumann 		int_vect_size = RV770_SMC_INT_VECTOR_SIZE;
50357e252bfSMichael Neumann 		break;
50457e252bfSMichael Neumann 	case CHIP_RV730:
50557e252bfSMichael Neumann 		ucode_start_address = RV730_SMC_UCODE_START;
50657e252bfSMichael Neumann 		ucode_size = RV730_SMC_UCODE_SIZE;
50757e252bfSMichael Neumann 		int_vect = (const u8 *)&rv730_smc_int_vectors;
50857e252bfSMichael Neumann 		int_vect_start_address = RV730_SMC_INT_VECTOR_START;
50957e252bfSMichael Neumann 		int_vect_size = RV730_SMC_INT_VECTOR_SIZE;
51057e252bfSMichael Neumann 		break;
51157e252bfSMichael Neumann 	case CHIP_RV710:
51257e252bfSMichael Neumann 		ucode_start_address = RV710_SMC_UCODE_START;
51357e252bfSMichael Neumann 		ucode_size = RV710_SMC_UCODE_SIZE;
51457e252bfSMichael Neumann 		int_vect = (const u8 *)&rv710_smc_int_vectors;
51557e252bfSMichael Neumann 		int_vect_start_address = RV710_SMC_INT_VECTOR_START;
51657e252bfSMichael Neumann 		int_vect_size = RV710_SMC_INT_VECTOR_SIZE;
51757e252bfSMichael Neumann 		break;
51857e252bfSMichael Neumann 	case CHIP_RV740:
51957e252bfSMichael Neumann 		ucode_start_address = RV740_SMC_UCODE_START;
52057e252bfSMichael Neumann 		ucode_size = RV740_SMC_UCODE_SIZE;
52157e252bfSMichael Neumann 		int_vect = (const u8 *)&rv740_smc_int_vectors;
52257e252bfSMichael Neumann 		int_vect_start_address = RV740_SMC_INT_VECTOR_START;
52357e252bfSMichael Neumann 		int_vect_size = RV740_SMC_INT_VECTOR_SIZE;
52457e252bfSMichael Neumann 		break;
52557e252bfSMichael Neumann 	case CHIP_CEDAR:
52657e252bfSMichael Neumann 		ucode_start_address = CEDAR_SMC_UCODE_START;
52757e252bfSMichael Neumann 		ucode_size = CEDAR_SMC_UCODE_SIZE;
52857e252bfSMichael Neumann 		int_vect = (const u8 *)&cedar_smc_int_vectors;
52957e252bfSMichael Neumann 		int_vect_start_address = CEDAR_SMC_INT_VECTOR_START;
53057e252bfSMichael Neumann 		int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE;
53157e252bfSMichael Neumann 		break;
53257e252bfSMichael Neumann 	case CHIP_REDWOOD:
53357e252bfSMichael Neumann 		ucode_start_address = REDWOOD_SMC_UCODE_START;
53457e252bfSMichael Neumann 		ucode_size = REDWOOD_SMC_UCODE_SIZE;
53557e252bfSMichael Neumann 		int_vect = (const u8 *)&redwood_smc_int_vectors;
53657e252bfSMichael Neumann 		int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START;
53757e252bfSMichael Neumann 		int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE;
53857e252bfSMichael Neumann 		break;
53957e252bfSMichael Neumann 	case CHIP_JUNIPER:
54057e252bfSMichael Neumann 		ucode_start_address = JUNIPER_SMC_UCODE_START;
54157e252bfSMichael Neumann 		ucode_size = JUNIPER_SMC_UCODE_SIZE;
54257e252bfSMichael Neumann 		int_vect = (const u8 *)&juniper_smc_int_vectors;
54357e252bfSMichael Neumann 		int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START;
54457e252bfSMichael Neumann 		int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE;
54557e252bfSMichael Neumann 		break;
54657e252bfSMichael Neumann 	case CHIP_CYPRESS:
54757e252bfSMichael Neumann 	case CHIP_HEMLOCK:
54857e252bfSMichael Neumann 		ucode_start_address = CYPRESS_SMC_UCODE_START;
54957e252bfSMichael Neumann 		ucode_size = CYPRESS_SMC_UCODE_SIZE;
55057e252bfSMichael Neumann 		int_vect = (const u8 *)&cypress_smc_int_vectors;
55157e252bfSMichael Neumann 		int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START;
55257e252bfSMichael Neumann 		int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE;
55357e252bfSMichael Neumann 		break;
55457e252bfSMichael Neumann 	case CHIP_BARTS:
55557e252bfSMichael Neumann 		ucode_start_address = BARTS_SMC_UCODE_START;
55657e252bfSMichael Neumann 		ucode_size = BARTS_SMC_UCODE_SIZE;
55757e252bfSMichael Neumann 		int_vect = (const u8 *)&barts_smc_int_vectors;
55857e252bfSMichael Neumann 		int_vect_start_address = BARTS_SMC_INT_VECTOR_START;
55957e252bfSMichael Neumann 		int_vect_size = BARTS_SMC_INT_VECTOR_SIZE;
56057e252bfSMichael Neumann 		break;
56157e252bfSMichael Neumann 	case CHIP_TURKS:
56257e252bfSMichael Neumann 		ucode_start_address = TURKS_SMC_UCODE_START;
56357e252bfSMichael Neumann 		ucode_size = TURKS_SMC_UCODE_SIZE;
56457e252bfSMichael Neumann 		int_vect = (const u8 *)&turks_smc_int_vectors;
56557e252bfSMichael Neumann 		int_vect_start_address = TURKS_SMC_INT_VECTOR_START;
56657e252bfSMichael Neumann 		int_vect_size = TURKS_SMC_INT_VECTOR_SIZE;
56757e252bfSMichael Neumann 		break;
56857e252bfSMichael Neumann 	case CHIP_CAICOS:
56957e252bfSMichael Neumann 		ucode_start_address = CAICOS_SMC_UCODE_START;
57057e252bfSMichael Neumann 		ucode_size = CAICOS_SMC_UCODE_SIZE;
57157e252bfSMichael Neumann 		int_vect = (const u8 *)&caicos_smc_int_vectors;
57257e252bfSMichael Neumann 		int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
57357e252bfSMichael Neumann 		int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
57457e252bfSMichael Neumann 		break;
57557e252bfSMichael Neumann 	case CHIP_CAYMAN:
57657e252bfSMichael Neumann 		ucode_start_address = CAYMAN_SMC_UCODE_START;
57757e252bfSMichael Neumann 		ucode_size = CAYMAN_SMC_UCODE_SIZE;
57857e252bfSMichael Neumann 		int_vect = (const u8 *)&cayman_smc_int_vectors;
57957e252bfSMichael Neumann 		int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START;
58057e252bfSMichael Neumann 		int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE;
58157e252bfSMichael Neumann 		break;
58257e252bfSMichael Neumann 	default:
58357e252bfSMichael Neumann 		DRM_ERROR("unknown asic in smc ucode loader\n");
58457e252bfSMichael Neumann 		BUG();
58557e252bfSMichael Neumann 	}
58657e252bfSMichael Neumann 
58757e252bfSMichael Neumann 	/* load the ucode */
58857e252bfSMichael Neumann 	ucode_data = (const u8 *)rdev->smc_fw->data;
58957e252bfSMichael Neumann 	ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address,
59057e252bfSMichael Neumann 				      ucode_data, ucode_size, limit);
59157e252bfSMichael Neumann 	if (ret)
59257e252bfSMichael Neumann 		return ret;
59357e252bfSMichael Neumann 
59457e252bfSMichael Neumann 	/* set up the int vectors */
59557e252bfSMichael Neumann 	ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address,
59657e252bfSMichael Neumann 					      int_vect, int_vect_size);
59757e252bfSMichael Neumann 	if (ret)
59857e252bfSMichael Neumann 		return ret;
59957e252bfSMichael Neumann 
60057e252bfSMichael Neumann 	return 0;
60157e252bfSMichael Neumann }
60257e252bfSMichael Neumann 
rv770_read_smc_sram_dword(struct radeon_device * rdev,u16 smc_address,u32 * value,u16 limit)60357e252bfSMichael Neumann int rv770_read_smc_sram_dword(struct radeon_device *rdev,
60457e252bfSMichael Neumann 			      u16 smc_address, u32 *value, u16 limit)
60557e252bfSMichael Neumann {
606a85cb24fSFrançois Tigeot 	unsigned long flags;
60757e252bfSMichael Neumann 	int ret;
60857e252bfSMichael Neumann 
609a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
61057e252bfSMichael Neumann 	ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
611c6f73aabSFrançois Tigeot 	if (ret == 0)
61257e252bfSMichael Neumann 		*value = RREG32(SMC_SRAM_DATA);
613a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
61457e252bfSMichael Neumann 
615c6f73aabSFrançois Tigeot 	return ret;
61657e252bfSMichael Neumann }
61757e252bfSMichael Neumann 
rv770_write_smc_sram_dword(struct radeon_device * rdev,u16 smc_address,u32 value,u16 limit)61857e252bfSMichael Neumann int rv770_write_smc_sram_dword(struct radeon_device *rdev,
61957e252bfSMichael Neumann 			       u16 smc_address, u32 value, u16 limit)
62057e252bfSMichael Neumann {
621a85cb24fSFrançois Tigeot 	unsigned long flags;
62257e252bfSMichael Neumann 	int ret;
62357e252bfSMichael Neumann 
624a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
62557e252bfSMichael Neumann 	ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
626c6f73aabSFrançois Tigeot 	if (ret == 0)
62757e252bfSMichael Neumann 		WREG32(SMC_SRAM_DATA, value);
628a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
62957e252bfSMichael Neumann 
630c6f73aabSFrançois Tigeot 	return ret;
63157e252bfSMichael Neumann }
632