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