Chameleon

Chameleon Commit Details

Date:2015-08-01 00:46:44 (8 years 8 months ago)
Author:ErmaC
Commit:2747
Parents: 2746
Message:Add HDA bus scans and codecs enumeration (Credits to Zenith432)
Changes:
M/branches/ErmaC/Enoch/CHANGES
M/branches/ErmaC/Enoch/i386/libsaio/hda.c
M/branches/ErmaC/Enoch/i386/libsaio/hda.h

File differences

branches/ErmaC/Enoch/i386/libsaio/hda.c
6262
6363
6464
65
6566
6667
6768
......
9495
9596
9697
97
98
9899
100
101
102
103
104
99105
100106
101107
......
258264
259265
260266
261
262267
263268
264269
......
592597
593598
594599
595
596600
597601
598602
......
650654
651655
652656
657
658
659
660
653661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
654749
655750
656751
......
697792
698793
699794
795
700796
701797
702798
......
879975
880976
881977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
#include "boot.h"
#include "bootstruct.h"
#include "cpu.h"
#include "pci.h"
#include "pci_root.h"
#include "platform.h"
#define CDBG(x...)
#endif
extern uint32_t devices_number;
#define UNKNOWN "Unknown "
#define hdacc_lock(codec) snd_mtxlock((codec)->lock)
#define hdacc_unlock(codec) snd_mtxunlock((codec)->lock)
#define hdacc_lockassert(codec) snd_mtxassert((codec)->lock)
#define hdacc_lockowned(codec) mtx_owned((codec)->lock)
const char *hda_slot_name[]={ "AAPL,slot-name", "Built In" };
uint8_t default_HDEF_layout_id[]={0x01, 0x00, 0x00, 0x00};
* --------------------------------
*/
/*
static hdacc_codecs know_codecs[] = {
{ HDA_CODEC_CS4206, 0,"CS4206" },
{ HDA_CODEC_CS4207, 0,"CS4207" },
};
#define HDACC_CODECS_LEN (sizeof(know_codecs) / sizeof(know_codecs[0]))
*/
/*****************
* Device Methods
return desc;
}
/* get Codec name */
static char *get_hda_codec_name( uint16_t codec_vendor_id, uint16_t codec_device_id, uint8_t codec_revision_id, uint8_t codec_stepping_id )
{
static char desc[128];
char*lName_format = NULL;
uint32_tlCodec_model = ((uint32_t)(codec_vendor_id) << 16) + (codec_device_id);
uint32_tlCodec_rev = (((uint16_t)(codec_revision_id) << 8) + codec_stepping_id);
int i;
// Get format for vendor ID
switch ( codec_vendor_id ) // uint16_t
{
case ANALOGDEVICES_VENDORID:
lName_format = "Analog Devices %s"; break;
case AGERE_VENDORID:
lName_format = "Agere Systems %s "; break;
case REALTEK_VENDORID:
lName_format = "Realtek %s"; break;
case ATI_VENDORID:
lName_format = "ATI %s"; break;
case CREATIVE_VENDORID:
lName_format = "Creative %s"; break;
case CMEDIA_VENDORID:
case CMEDIA2_VENDORID:
lName_format = "CMedia %s"; break;
case CIRRUSLOGIC_VENDORID:
lName_format = "Cirrus Logic %s"; break;
case CONEXANT_VENDORID:
lName_format = "Conexant %s"; break;
case CHRONTEL_VENDORID:
lName_format = "Chrontel %s"; break;
case IDT_VENDORID:
lName_format = "IDT %s"; break;
case INTEL_VENDORID:
lName_format = "Intel %s"; break;
case MOTO_VENDORID:
lName_format = "Motorola %s"; break;
case NVIDIA_VENDORID:
lName_format = "nVidia %s"; break;
case SII_VENDORID:
lName_format = "Silicon Image %s"; break;
case SIGMATEL_VENDORID:
lName_format = "Sigmatel %s"; break;
case VIA_VENDORID:
lName_format = "VIA %s"; break;
default:
lName_format = UNKNOWN; break;
break;
}
for (i = 0; i < HDACC_CODECS_LEN; i++)
{
if ( know_codecs[i].id == lCodec_model )
{
if ( ( know_codecs[i].rev == 0x00000000 ) || ( know_codecs[i].rev == lCodec_rev ) )
{
//verbose("\tRevision in table (%06x) | burned chip revision (%06x).\n", know_codecs[i].rev, lCodec_rev );
snprintf(desc, sizeof(desc), lName_format, know_codecs[i].name);
return desc;
}
}
}
if ( ( lName_format != UNKNOWN ) && ( strstr(lName_format, "%s" ) != NULL ) )
{
// Dirty way to remove '%s' from the end of the lName_format
int len = strlen(lName_format);
lName_format[len-2] = '\0';
}
// Not in table
snprintf(desc, sizeof(desc), "unknown %s Codec", lName_format);
return desc;
}
bool setup_hda_devprop(pci_dt_t *hda_dev)
{
structDevPropDevice*device = NULL;
controller_name, hda_dev->vendor_id, hda_dev->device_id, hda_dev->revision_id,
hda_dev->subsys_id.subsys.vendor_id, hda_dev->subsys_id.subsys.device_id, devicepath);
probe_hda_bus(hda_dev->dev.addr);
switch ((controller_device_id << 16) | controller_vendor_id)
{
return true;
}
/*
* Structure of HDA MMIO Region
*/
struct HDARegs
{
uint16_t gcap;
uint8_t vmin;
uint8_t vmaj;
uint16_t outpay;
uint16_t inpay;
uint32_t gctl;
uint16_t wakeen;
uint16_t statests;
uint16_t gsts;
uint8_t rsvd0[6];
uint16_t outstrmpay;
uint16_t instrmpay;
uint8_t rsvd1[4];
uint32_t intctl;
uint32_t intsts;
uint8_t rsvd2[8];
uint32_t walclk;
uint8_t rsvd3[4];
uint32_t ssync;
uint8_t rsvd4[4];
uint32_t corblbase;
uint32_t corbubase;
uint16_t corbwp;
uint16_t corbrp;
uint8_t corbctl;
uint8_t corbsts;
uint8_t corbsize;
uint8_t rsvd5;
uint32_t rirblbase;
uint32_t rirbubase;
uint16_t rirbwp;
uint16_t rintcnt;
uint8_t rirbctl;
uint8_t rirbsts;
uint8_t rirbsize;
uint8_t rsvd6;
uint32_t icoi;
uint32_t icii;
uint16_t icis;
uint8_t rsvd7[6];
uint32_t dpiblbase;
uint32_t dpibubase;
uint8_t rsvd8[8];
/*
* Stream Descriptors follow
*/
} __attribute__((aligned(16), packed));
/*
* Data to be discovered for HDA codecs
*/
struct HDACodecInfo
{
uint16_t vendor_id;
uint16_t device_id;
uint8_t revision_id;
uint8_t stepping_id;
uint8_t maj_rev;
uint8_t min_rev;
uint8_t num_function_groups;
const char *name;
};
/*
* Timing Functions
*/
static int wait_for_register_state_16(uint16_t const volatile* reg,
uint16_t target_mask,
uint16_t target_value,
uint32_t timeout_us,
uint32_t tsc_ticks_per_us)
{
uint64_t deadline = rdtsc64() + MultU32x32(timeout_us, tsc_ticks_per_us);
do
{
uint16_t value = *reg;
if ((value & target_mask) == target_value)
return 0;
CpuPause();
}
while (rdtsc64() < deadline);
return -1;
}
static void delay_us(uint32_t timeout_us, uint32_t tsc_ticks_per_us)
{
uint64_t deadline = rdtsc64() + MultU32x32(timeout_us, tsc_ticks_per_us);
do
{
CpuPause();
}
while (rdtsc64() < deadline);
}
static struct HDARegs volatile* hdaMemory = NULL;
static uint32_t tsc_ticks_per_us = 0U;
#define ICIS_ICB 1U
#define ICIS_IRV 2U
static int immediate_command(uint32_t command, uint32_t* response)
{
/*
* Wait up to 1ms for for ICB 0
*/
(void) wait_for_register_state_16(&hdaMemory->icis, ICIS_ICB, 0U, 1000U, tsc_ticks_per_us);
/*
* Ignore timeout and force ICB to 0
* Clear IRV while at it
*/
hdaMemory->icis = ICIS_IRV;
/*
* Program command
*/
hdaMemory->icoi = command;
/*
* Trigger command
* Clear IRV again just in case
*/
hdaMemory->icis = ICIS_ICB | ICIS_IRV;
/*
* Wait up to 1ms for response
*/
if (wait_for_register_state_16(&hdaMemory->icis, ICIS_IRV, ICIS_IRV, 1000U, tsc_ticks_per_us) < 0)
{
/*
* response timed out
*/
return -1;
}
*response = hdaMemory->icii;
return 0;
}
#define PACK_CID(x) ((x & 15U) << 28)
#define PACK_NID(x) ((x & 127U) << 20)
#define PACK_VERB_12BIT(x) ((x & 4095U) << 8)
#define PACK_PAYLOAD_8BIT(x) (x & UINT8_MAX)
#define VERB_GET_PARAMETER 0xF00U
static uint32_t get_parameter(uint8_t codec_id, uint8_t node_id, uint8_t parameter_id)
{
uint32_t command, response;
command = PACK_CID(codec_id) | PACK_NID(node_id) | PACK_VERB_12BIT(VERB_GET_PARAMETER) | PACK_PAYLOAD_8BIT(parameter_id);
response = UINT32_MAX;
/*
* Ignore timeout, return UINT32_MAX as error value
*/
(void) immediate_command(command, &response);
return response;
}
#define PARAMETER_VID_DID 0U
#define PARAMETER_RID 2U
#define PARAMETER_NUM_NODES 4U
static void probe_hda_codec(uint8_t codec_id, struct HDACodecInfo *codec_info)
{
uint32_t response;
CDBG("\tprobing codec %d\n", codec_id);
response = get_parameter(codec_id, 0U, PARAMETER_VID_DID);
codec_info->vendor_id = (response >> 16) & UINT16_MAX;
codec_info->device_id = response & UINT16_MAX;
response = get_parameter(codec_id, 0U, PARAMETER_RID);
codec_info->revision_id = (response >> 8) & UINT8_MAX;
codec_info->stepping_id = response & UINT8_MAX;
codec_info->maj_rev = (response >> 20) & 15U;
codec_info->min_rev = (response >> 16) & 15U;
response = get_parameter(codec_id, 0U, PARAMETER_NUM_NODES);
codec_info->num_function_groups = response & UINT8_MAX;
codec_info->name = get_hda_codec_name(codec_info->vendor_id, codec_info->device_id, codec_info->revision_id, codec_info->stepping_id);
}
static int getHDABar(uint32_t pci_addr, uint32_t* bar_phys_addr)
{
uint32_t barlow = pci_config_read32(pci_addr, PCI_BASE_ADDRESS_0);
if ((barlow & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY)
{
CDBG("\tBAR0 for HDA Controller 0x%x is not an MMIO space\n", pci_addr);
return -1;
}
if ((barlow & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
{
uint32_t barhigh = pci_config_read32(pci_addr, PCI_BASE_ADDRESS_1);
if (barhigh)
{
//verbose("\tBAR0 for HDA Controller 0x%x is located ouside 32-bit physical address space (0x%x%08x)\n",
//pci_addr, barhigh, barlow & PCI_BASE_ADDRESS_MEM_MASK);
return -1;
}
}
if (bar_phys_addr)
{
*bar_phys_addr = (barlow & PCI_BASE_ADDRESS_MEM_MASK);
}
return 0;
}
void probe_hda_bus(uint32_t pci_addr)
{
uint64_t tsc_frequency;
uint32_t bar_phys_addr;
uint16_t pci_cmd, statests;
uint16_t const pci_cmd_wanted = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
uint8_t codec_id, original_reset_state;
struct HDACodecInfo codec_info;
CDBG("\tlooking for HDA bar0 on pci_addr 0x%x\n", pci_addr);
if (getHDABar(pci_addr, &bar_phys_addr) < 0)
{
return;
}
CDBG("\tfound HDA memory at 0x%x\n", bar_phys_addr);
hdaMemory = (struct HDARegs volatile*) bar_phys_addr;
tsc_frequency = Platform.CPU.TSCFrequency;
tsc_ticks_per_us = DivU64x32(tsc_frequency, 1000000U); // TSC ticks per microsecond
CDBG("\ttsc_ticks_per_us %d\n", tsc_ticks_per_us);
/*
* Enable Memory Space and Bus Mastering
*/
pci_cmd = pci_config_read16(pci_addr, PCI_COMMAND);
if ((pci_cmd & pci_cmd_wanted) != pci_cmd_wanted)
{
pci_cmd |= pci_cmd_wanted;
pci_config_write16(pci_addr, PCI_COMMAND, pci_cmd);
}
/*
* Remember entering reset state
*/
original_reset_state = (hdaMemory->gctl & HDAC_GCTL_CRST) ? 1U : 0U;
/*
* Reset HDA Controller
*/
hdaMemory->wakeen = 0U;
hdaMemory->statests = UINT16_MAX;
hdaMemory->gsts = UINT16_MAX;
hdaMemory->intctl = 0U;
CDBG("\tStarting reset\n");
hdaMemory->gctl = 0U;
/*
* Wait up to 10ms to enter Reset
*/
if (wait_for_register_state_16((uint16_t volatile const*) &hdaMemory->gctl,
HDAC_GCTL_CRST,
0U,
10000U,
tsc_ticks_per_us) < 0)
{
CDBG("\tHDA Controller 0x%x timed out 10ms entering reset\n", pci_addr);
return;
}
CDBG("\tReset asserted, delay 100us\n");
/*
* Delay 2400 BCLK (100us)
*/
delay_us(100U, tsc_ticks_per_us);
CDBG("\tDeasserting reset\n");
/*
* Wait up to 10ms to exit Reset
*/
hdaMemory->gctl = HDAC_GCTL_CRST;
if (wait_for_register_state_16((uint16_t volatile const*) &hdaMemory->gctl,
HDAC_GCTL_CRST,
HDAC_GCTL_CRST,
10000U,
tsc_ticks_per_us) < 0)
{
CDBG("\tHDA Controller 0x%x timed out 10ms exiting reset\n", pci_addr);
return;
}
CDBG("\tReset complete\n");
/*
* Wait 1ms for codecs to request enumeration (spec says 521us).
*/
delay_us(1000U, tsc_ticks_per_us);
/*
* See which codecs want enumeration
*/
statests = hdaMemory->statests;
hdaMemory->statests = statests; // clear statests
CDBG("\tstatests is now 0x%x\n", statests);
codec_id = 0U;
while (statests)
{
if (statests & 1U)
{
probe_hda_codec(codec_id, &codec_info);
verbose("\tFound %s (%04x%04x), rev(%04x)",
codec_info.name,
codec_info.vendor_id,
codec_info.device_id,
codec_info.revision_id);
#if DEBUG_CODEC
verbose(", stepping 0x%x, major rev 0x%x, minor rev 0x%x, %d function groups",
codec_info.stepping_id,
codec_info.maj_rev,
codec_info.min_rev,
codec_info.num_function_groups);
#endif
verbose("\n");
}
++codec_id;
statests >>= 1;
}
/*
* Restore reset state entered with
*/
if (!original_reset_state)
{
hdaMemory->gctl = 0U;
}
}
branches/ErmaC/Enoch/i386/libsaio/hda.h
6262
6363
6464
65
65
66
67
68
69
70
71
6672
6773
6874
......
7379
7480
7581
76
7782
7883
7984
......
8186
8287
8388
84
8589
8690
8791
......
974978
975979
976980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
9771027
#ifndef __LIBSAIO_HDA_H
#define __LIBSAIO_HDA_H
bool setup_hda_devprop(pci_dt_t *hda_dev);
static char *get_hda_controller_name( uint16_t controller_device_id, uint16_t controller_vendor_id );
static char *get_hda_codec_name( uint16_t codec_vendor_id, uint16_t codec_device_id, uint8_t codec_revision_id, uint8_t codec_stepping_id );
bool setup_hda_devprop( pci_dt_t *hda_dev );
static int immediate_command(uint32_t command, uint32_t* response);
static uint32_t get_parameter(uint8_t codec_id, uint8_t node_id, uint8_t parameter_id);
static int getHDABar(uint32_t pci_addr, uint32_t* bar_phys_addr);
void probe_hda_bus(uint32_t pci_addr);
struct hda_controller_devices;
typedef struct
// charquirks_off;
} hda_controller_devices;
/*
struct hdacc_codecs;
typedef struct
{
uint32_t rev;
const char *name;
} hdacc_codecs;
*/
/****************************************************************************
* Miscellanious defines
#define HDAC_SDSTS_FIFOE(1 << 3)
#define HDAC_SDSTS_BCIS(1 << 2)
/****************************************************************************
* Helper Macros
****************************************************************************/
#define HDA_DMA_ALIGNMENT 128
#define HDA_BDL_MIN 2
#define HDA_BDL_MAX 256
#define HDA_BDL_DEFAULT HDA_BDL_MIN
#define HDA_BLK_MIN HDA_DMA_ALIGNMENT
#define HDA_BLK_ALIGN (~(HDA_BLK_MIN - 1))
#define HDA_BUFSZ_MIN (HDA_BDL_MIN * HDA_BLK_MIN)
#define HDA_BUFSZ_MAX 262144
#define HDA_BUFSZ_DEFAULT 65536
#define HDA_GPIO_MAX 8
#define HDA_DEV_MATCH(fl, v) ((fl) == (v) || \
(fl) == 0xffffffff || \
(((fl) & 0xffff0000) == 0xffff0000 && \
((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \
(((fl) & 0x0000ffff) == 0x0000ffff && \
((fl) & 0xffff0000) == ((v) & 0xffff0000)))
#define HDA_MATCH_ALL 0xffffffff
#define HDA_INVALID 0xffffffff
#define HDA_BOOTVERBOSE(stmt) do { \
if (bootverbose != 0 || snd_verbose > 3) { \
stmt \
} \
} while (0)
#define HDA_BOOTHVERBOSE(stmt) do { \
if (snd_verbose > 3) { \
stmt \
} \
} while (0)
#define hda_command(dev, verb) \
HDAC_CODEC_COMMAND(device_get_parent(dev), (dev), (verb))
extern void probe_hda_bus(uint32_t pci_addr);
#endif /* !__LIBSAIO_HDA_H */
branches/ErmaC/Enoch/CHANGES
1
12
23
34
- Zenith432 : HDA bus scans and codecs enumeration.
- Pike R. Alpha : Add support for (LZVN) grey logo.
- Slice : Added NvidiaSingle
- cparm : Rock - Paper - Scissors algo

Archive Download the corresponding diff file

Revision: 2747