|
| 1 | +#include <sof/lib/dai-legacy.h> |
| 2 | +#include <sof/drivers/afe-drv.h> |
| 3 | +#include <stdio.h> |
| 4 | + |
| 5 | +/* DIY assertion, an "assert()" is already defined in platform headers */ |
| 6 | +#define CHECK(expr) if(!(expr)) { \ |
| 7 | + printf("FAILED: " #expr " at line %d\n", __LINE__); *(int*)0=0; } |
| 8 | + |
| 9 | +/* These are the symbols we need to enumerate */ |
| 10 | +extern struct mtk_base_afe_platform mtk_afe_platform; |
| 11 | +extern const struct dai_info lib_dai; |
| 12 | + |
| 13 | +/* Call this to initialize the dai arrays */ |
| 14 | +int dai_init(struct sof *sof); |
| 15 | + |
| 16 | +/* Debug hook in some versions of MTK firmware */ |
| 17 | +void printf_(void) {} |
| 18 | + |
| 19 | +/* Just need a pointer to a symbol with this name */ |
| 20 | +int afe_dai_driver; |
| 21 | + |
| 22 | +/* So dai_init() can write to something */ |
| 23 | +struct sof sof; |
| 24 | + |
| 25 | +unsigned int afe_base_addr; |
| 26 | + |
| 27 | +void symify(char *s) |
| 28 | +{ |
| 29 | + for(; *s; s++) { |
| 30 | + if (*s >= 'A' && *s <= 'Z') |
| 31 | + *s += 'a' - 'A'; |
| 32 | + CHECK((*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9') || *s == '_'); |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +/* The AFE driver has some... idiosyncratic defaulting. The existing |
| 37 | + * configurations have a varying set of conventions to encode "no |
| 38 | + * value is set": |
| 39 | + * |
| 40 | + * ch_num is skipped if the stored reg value is negative |
| 41 | + * quad_ch is skipped if the mask is zero |
| 42 | + * int_odd: <=0 reg |
| 43 | + * mono: <=0 reg OR <=0 shift |
| 44 | + * msb: <=0 reg |
| 45 | + * msb2: <=0 reg |
| 46 | + * agent_disable: <=0 reg |
| 47 | + * fs: never skipped |
| 48 | + * hd: never skipped |
| 49 | + * enable: never skipped |
| 50 | + * |
| 51 | + * We detect the union of those conditions and elide the setting (it |
| 52 | + * will be defaulted to reg=-1/shift=0/mask=0 in the driver DTS macros) |
| 53 | + */ |
| 54 | +void print_fld(const char *name, int reg, int shift, int lomask) |
| 55 | +{ |
| 56 | + if (reg <= 0 || shift < 0 || lomask == 0) { |
| 57 | + return; |
| 58 | + } |
| 59 | + |
| 60 | + int bits = __builtin_ffs(lomask + 1) - 1; |
| 61 | + |
| 62 | + CHECK(((lomask + 1) & lomask) == 0); // must be power of two |
| 63 | + CHECK(lomask); // and not zero |
| 64 | + CHECK(shift >= 0 && (shift + bits) <= 32); // and shift doesn't overrun |
| 65 | + |
| 66 | + printf("\t\t" "%s = <0x%8.8x %d %d>;\n", |
| 67 | + name, reg + afe_base_addr, shift, bits); |
| 68 | +} |
| 69 | + |
| 70 | +unsigned int msbaddr(int val) |
| 71 | +{ |
| 72 | + return val ? val + afe_base_addr : 0; |
| 73 | +} |
| 74 | + |
| 75 | +int main(void) |
| 76 | +{ |
| 77 | + dai_init(&sof); |
| 78 | + |
| 79 | + afe_base_addr = mtk_afe_platform.base_addr; |
| 80 | + |
| 81 | + // The DAI order here is immutable: the indexes are known to and |
| 82 | + // used by the kernel driver. And these point to the memif array |
| 83 | + // via an index stored in the low byte (?!) of the first fifo's |
| 84 | + // "handshake" (it's not a DMA handshake value at all). So we |
| 85 | + // invert the mapping and store the dai index along with the AFE |
| 86 | + // record. |
| 87 | + int dai_memif[64]; |
| 88 | + int num_dais = 0; |
| 89 | + for (int t = 0; t < lib_dai.num_dai_types; t++) { |
| 90 | + for (int i = 0; i < lib_dai.dai_type_array[t].num_dais; i++) { |
| 91 | + int idx = lib_dai.dai_type_array[t].dai_array[i].index; |
| 92 | + int hs = lib_dai.dai_type_array[t].dai_array[i].plat_data.fifo[0].handshake; |
| 93 | + |
| 94 | + CHECK(idx == num_dais); |
| 95 | + dai_memif[num_dais++] = hs >> 16; |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + // Quick check that the dai/memif mapping is unique |
| 100 | + for(int i=0; i<num_dais; i++) { |
| 101 | + int n = 0; |
| 102 | + for(int j=0; j<num_dais; j++) |
| 103 | + if(dai_memif[j] == i) |
| 104 | + n++; |
| 105 | + CHECK(n == 1); |
| 106 | + } |
| 107 | + |
| 108 | + for (int i = 0; i < mtk_afe_platform.memif_size; i++) { |
| 109 | + const struct mtk_base_memif_data *m = &mtk_afe_platform.memif_datas[i]; |
| 110 | + |
| 111 | + int dai_id = -1; |
| 112 | + for (int j = 0; j < num_dais; j++) { |
| 113 | + if (dai_memif[j] == i) { |
| 114 | + dai_id = j; |
| 115 | + break; |
| 116 | + } |
| 117 | + } |
| 118 | + CHECK(dai_id >= 0); |
| 119 | + |
| 120 | + // We use the UL/DL naming to detect direction, make sure it isn't broken |
| 121 | + bool uplink = !!strstr(m->name, "UL"); |
| 122 | + bool downlink = !!strstr(m->name, "DL"); |
| 123 | + CHECK(uplink != downlink); |
| 124 | + |
| 125 | + // Validate and lower-case the name to make a DTS symbol |
| 126 | + char sym[64]; |
| 127 | + CHECK(strlen(m->name) < sizeof(sym)); |
| 128 | + strcpy(sym, m->name); |
| 129 | + symify(sym); |
| 130 | + |
| 131 | + //printf("memif %d %s dai %d %s\n", i, sym, dai_id, downlink ? "downlink" : ""); |
| 132 | + |
| 133 | + printf("\t" "afe_%s: afe_%s {\n", sym, sym); |
| 134 | + printf("\t\t" "compatible = \"mediatek,afe\";\n"); |
| 135 | + printf("\t\t" "afe_name = \"%s\";\n", m->name); |
| 136 | + printf("\t\t" "dai_id = <%d>;\n", dai_id); |
| 137 | + if (downlink) |
| 138 | + printf("\t\t" "downlink;\n"); |
| 139 | + |
| 140 | + /* Register pairs containing the high and low words of |
| 141 | + * bus/host addresses. The first (high) register is allowed |
| 142 | + * to be zero indicating all addresses will be 32 bit. |
| 143 | + */ |
| 144 | + printf("\t\t" "base = <0x%8.8x 0x%8.8x>;\n", |
| 145 | + msbaddr(m->reg_ofs_base_msb), m->reg_ofs_base + afe_base_addr); |
| 146 | + printf("\t\t" "cur = <0x%8.8x 0x%8.8x>;\n", |
| 147 | + msbaddr(m->reg_ofs_cur_msb), m->reg_ofs_cur + afe_base_addr); |
| 148 | + printf("\t\t" "end = <0x%8.8x 0x%8.8x>;\n", |
| 149 | + msbaddr(m->reg_ofs_end_msb), m->reg_ofs_end + afe_base_addr); |
| 150 | + |
| 151 | + print_fld("fs", m->fs_reg, m->fs_shift, m->fs_maskbit); |
| 152 | + print_fld("mono", m->mono_reg, m->mono_shift, 1); |
| 153 | + if (m->mono_invert) |
| 154 | + printf("\t\t" "mono_invert;\n"); |
| 155 | + print_fld("quad_ch", m->quad_ch_reg, m->quad_ch_shift, m->quad_ch_mask); |
| 156 | + print_fld("int_odd", m->int_odd_flag_reg, m->int_odd_flag_shift, 1); |
| 157 | + print_fld("enable", m->enable_reg, m->enable_shift, 1); |
| 158 | + print_fld("hd", m->hd_reg, m->hd_shift, 1); |
| 159 | + print_fld("msb", m->msb_reg, m->msb_shift, 1); |
| 160 | + print_fld("msb2", m->msb2_reg, m->msb2_shift, 1); |
| 161 | + print_fld("agent_disable", m->agent_disable_reg, m->agent_disable_shift, 1); |
| 162 | + print_fld("ch_num", m->ch_num_reg, m->ch_num_shift, m->ch_num_maskbit); |
| 163 | + |
| 164 | + // Note: there are also "pbuf" and "minlen" registers defined |
| 165 | + // in the memif_data struct, but they are unused by the |
| 166 | + // existing driver. |
| 167 | + |
| 168 | + printf("\t" "};\n\n"); |
| 169 | + } |
| 170 | +} |
| 171 | + |
0 commit comments