Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
stfm audio
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index e611694..bf37b3a 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1873,6 +1873,11 @@ static int radio_callback(int btn, struct gui_synclist *lists)
struct stfm1000_dbg_info nfo;
stfm1000_dbg_info(&nfo);
simplelist_addline(SIMPLELIST_ADD_LINE, "STFM1000 regs:");
+ simplelist_addline(SIMPLELIST_ADD_LINE,"tune1: 0x%x", nfo.tune1);
+ simplelist_addline(SIMPLELIST_ADD_LINE,"sdnominal: 0x%x", nfo.sdnominal);
+ simplelist_addline(SIMPLELIST_ADD_LINE,"pilottracking: 0x%x", nfo.pilottracking);
+ simplelist_addline(SIMPLELIST_ADD_LINE,"rssi_tone: 0x%x", nfo.rssi_tone);
+ simplelist_addline(SIMPLELIST_ADD_LINE,"pilotcorrection: 0x%x", nfo.pilotcorrection);
simplelist_addline(SIMPLELIST_ADD_LINE,"chipid: 0x%x", nfo.chipid);
}
#endif /* STFM1000 */
diff --git a/firmware/SOURCES b/firmware/SOURCES
index c2bd459..c5e7617 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -525,6 +525,7 @@ target/arm/imx233/lradc-imx233.c
target/arm/imx233/pwm-imx233.c
target/arm/imx233/rtc-imx233.c
target/arm/imx233/dcp-imx233.c
+target/arm/imx233/dri-imx233.c
# ifdef HAVE_TOUCHSCREEN
target/arm/imx233/touchscreen-imx233.c
# endif
diff --git a/firmware/drivers/tuner/stfm1000.c b/firmware/drivers/tuner/stfm1000.c
index 8626d4e..14cc9da 100644
--- a/firmware/drivers/tuner/stfm1000.c
+++ b/firmware/drivers/tuner/stfm1000.c
@@ -30,12 +30,17 @@
#include "fmradio.h"
#include "fmradio_i2c.h" /* physical interface driver */
#include "stfm1000.h"
+#include "stfm1000-regs.h"
-#define STFM100_I2C_ADDR 0xc0
+#include "stfm1000-tunetable.c"
+
+static int rev_id;
+static int sdnominal_pivot;
+static bool tuner_present = false;
-#define CHIPID 0x80
+#define STFM100_I2C_ADDR 0xc0
-static int stfm1000_read_reg(uint8_t reg, uint32_t *val)
+static int stfm1000_read(uint8_t reg, uint32_t *val)
{
uint8_t buf[4];
buf[0] = reg;
@@ -46,7 +51,7 @@ static int stfm1000_read_reg(uint8_t reg, uint32_t *val)
return ret;
}
-static int stfm1000_write_reg(uint8_t reg, uint32_t val)
+static int stfm1000_write(uint8_t reg, uint32_t val)
{
uint8_t buf[5];
buf[0] = reg;
@@ -55,25 +60,467 @@ static int stfm1000_write_reg(uint8_t reg, uint32_t val)
return fmradio_i2c_write(STFM100_I2C_ADDR, buf, 5);
}
+static int stfm1000_write_masked(int reg, int val, int mask)
+{
+ uint32_t tmp;
+
+ stfm1000_read(reg, &tmp);
+ stfm1000_write(reg, (val & mask) | (tmp & ~mask));
+ return 0;
+}
+
+static int stfm1000_set_bits(int reg, uint32_t value)
+{
+ return stfm1000_write_masked(reg, value, value);
+}
+
+static int stfm1000_clear_bits(int reg, uint32_t value)
+{
+ return stfm1000_write_masked(reg, ~value, value);
+}
+
+static void stfm1000_set_region(int region)
+{
+ const struct fm_region_data *rd = &fm_region_data[region];
+
+ if (rd->deemphasis == 50) {
+ stfm1000_set_bits(STFM1000_INITIALIZATION2, STFM1000_DEEMPH_50_75B);
+ } else {
+ stfm1000_clear_bits(STFM1000_INITIALIZATION2, STFM1000_DEEMPH_50_75B);
+ }
+}
+
+
+static int stfm1000_set_frequency(int freq)
+{
+ uint32_t freq100 = freq / 100;
+ int tune_cap;
+ int i2s_clock;
+ int mix_reg;
+ int if_freq, fe_freq;
+ uint32_t tune1, sdnom, agc1;
+ const struct stfm1000_tune1 *tp;
+ int ret;
+
+ if_freq = 0;
+ mix_reg = 1;
+ switch (mix_reg) {
+ case 0: if_freq = -2; break;
+ case 1: if_freq = -1; break;
+ case 2: if_freq = 0; break;
+ case 3: if_freq = 1; break;
+ case 4: if_freq = 2; break;
+ }
+
+ fe_freq = freq100 + if_freq;
+
+ /* clamp into range */
+ if (fe_freq < STFM1000_FREQUENCY_100KHZ_MIN)
+ fe_freq = STFM1000_FREQUENCY_100KHZ_MIN;
+ else if (fe_freq > STFM1000_FREQUENCY_100KHZ_MAX)
+ fe_freq = STFM1000_FREQUENCY_100KHZ_MAX;
+
+ tp = &stfm1000_tune1_table[fe_freq - STFM1000_FREQUENCY_100KHZ_MIN];
+
+ /* bits [14:0], [20:18] */
+ tune1 = (tp->tune1 & 0x7fff) | (mix_reg << 18);
+ sdnom = tp->sdnom;
+
+ agc1 = (rev_id == STFM1000_CHIP_REV_TA2) ? 0x0400 : 0x2200;
+
+ ret = stfm1000_write_masked(STFM1000_AGC_CONTROL1, agc1, 0x3f00);
+ if (ret != 0)
+ goto err;
+
+ ret = stfm1000_write_masked(STFM1000_TUNE1, tune1, 0xFFFF7FFF); /* do not set bit-15 */
+ if (ret != 0)
+ goto err;
+
+ /* keep this around */
+ sdnominal_pivot = sdnom;
+
+ ret = stfm1000_write(STFM1000_SDNOMINAL, sdnom);
+ if (ret != 0)
+ goto err;
+
+ /* fix for seek-not-stopping on alternate tunings */
+ ret = stfm1000_set_bits(STFM1000_DATAPATH, STFM1000_DB_ACCEPT);
+ if (ret != 0)
+ goto err;
+
+ ret = stfm1000_clear_bits(STFM1000_DATAPATH, STFM1000_DB_ACCEPT);
+ if (ret != 0)
+ goto err;
+
+ ret = stfm1000_set_bits(STFM1000_INITIALIZATION2, STFM1000_DRI_CLK_EN);
+ if (ret != 0)
+ goto err;
+
+ /* 6MHz spur fix */
+ if ((freq100 >= 778 && freq100 <= 782) ||
+ (freq100 >= 838 && freq100 <= 842) ||
+ (freq100 >= 898 && freq100 <= 902) ||
+ (freq100 >= 958 && freq100 <= 962) ||
+ (freq100 >= 1018 && freq100 <= 1022) ||
+ (freq100 >= 1078 && freq100 <= 1080))
+ i2s_clock = 5; /* 4.8MHz */
+ else
+ i2s_clock = 4;
+
+ ret = stfm1000_write_masked(STFM1000_DATAPATH,
+ STFM1000_SAI_CLK_DIV(i2s_clock), STFM1000_SAI_CLK_DIV_MASK);
+ if (ret != 0)
+ goto err;
+
+ ret = stfm1000_set_bits(STFM1000_INITIALIZATION2, STFM1000_DRI_CLK_EN);
+ if (ret != 0)
+ goto err;
+
+ if (tune1 & 0xf)
+ ret = stfm1000_set_bits(STFM1000_CLK1, STFM1000_ENABLE_TAPDELAYFIX);
+ else
+ ret = stfm1000_clear_bits(STFM1000_CLK1, STFM1000_ENABLE_TAPDELAYFIX);
+
+ if (ret != 0)
+ goto err;
+
+ tune_cap = 4744806 - (4587 * freq100);
+ if (tune_cap < 4)
+ tune_cap = 4;
+ ret = stfm1000_write_masked(STFM1000_LNA, STFM1000_ANTENNA_TUNECAP(tune_cap),
+ STFM1000_ANTENNA_TUNECAP_MASK);
+ if (ret != 0)
+ goto err;
+
+ return 0;
+err:
+ return -1;
+}
+
void stfm1000_dbg_info(struct stfm1000_dbg_info *nfo)
{
memset(nfo, 0, sizeof(struct stfm1000_dbg_info));
- stfm1000_read_reg(CHIPID, &nfo->chipid);
+ stfm1000_read(STFM1000_TUNE1, &nfo->tune1);
+ stfm1000_read(STFM1000_SDNOMINAL, &nfo->sdnominal);
+ stfm1000_read(STFM1000_PILOTTRACKING, &nfo->pilottracking);
+ stfm1000_read(STFM1000_RSSI_TONE, &nfo->rssi_tone);
+ stfm1000_read(STFM1000_PILOTCORRECTION, &nfo->pilotcorrection);
+ stfm1000_read(STFM1000_CHIPID, &nfo->chipid);
+}
+
+static void stfm1000_dp_enable(bool enable)
+{
+ if (enable) {
+ stfm1000_set_bits(STFM1000_DATAPATH, STFM1000_DP_EN);
+ sleep(1);
+ stfm1000_set_bits(STFM1000_DATAPATH, STFM1000_DB_ACCEPT);
+ stfm1000_clear_bits(STFM1000_AGC_CONTROL1, STFM1000_B2_BYPASS_AGC_CTL);
+ stfm1000_clear_bits(STFM1000_DATAPATH, STFM1000_DB_ACCEPT);
+ } else {
+ stfm1000_set_bits(STFM1000_DATAPATH, STFM1000_DB_ACCEPT);
+ stfm1000_clear_bits(STFM1000_DATAPATH, STFM1000_DP_EN);
+ stfm1000_set_bits(STFM1000_AGC_CONTROL1, STFM1000_B2_BYPASS_AGC_CTL);
+ stfm1000_clear_bits(STFM1000_PILOTTRACKING, STFM1000_B2_PILOTTRACKING_EN);
+ stfm1000_clear_bits(STFM1000_DATAPATH, STFM1000_DB_ACCEPT);
+ }
+}
+
+static void stfm_dri_enable(bool enable)
+{
+ if (enable) {
+ stfm1000_set_bits(STFM1000_DATAPATH, STFM1000_SAI_EN);
+ } else {
+ stfm1000_clear_bits(STFM1000_DATAPATH, STFM1000_SAI_EN);
+ }
+}
+
+static int stfm1000_set_channel_filter(void)
+{
+ int ret;
+ int bypass_setting;
+
+ /* get near channel amplitude */
+ ret = stfm1000_write_masked(STFM1000_INITIALIZATION3,
+ STFM1000_B2_NEAR_CHAN_MIX(0x01),
+ STFM1000_B2_NEAR_CHAN_MIX_MASK);
+ if (ret != 0)
+ return ret;
+
+ sleep(10 * HZ / 1000); /* wait for the signal quality to settle */
+
+ bypass_setting = 0;
+
+#if 0
+ ret = stfm1000_read(STFM1000_SIGNALQUALITY, &tmp);
+ if (ret != 0)
+ return ret;
+
+ sig_qual = (tmp & STFM1000_NEAR_CHAN_AMPLITUDE_MASK) >>
+ STFM1000_NEAR_CHAN_AMPLITUDE_SHIFT;
+
+ /* check near channel amplitude vs threshold */
+ if (sig_qual < stfm1000->adj_chan_th) {
+ /* get near channel amplitude again */
+ ret = stfm1000_write_masked(stfm1000, STFM1000_INITIALIZATION3,
+ STFM1000_B2_NEAR_CHAN_MIX(0x05),
+ STFM1000_B2_NEAR_CHAN_MIX_MASK);
+ if (ret != 0)
+ return ret;
+
+ msleep(10); /* wait for the signal quality to settle */
+
+ ret = stfm1000_read(stfm1000, STFM1000_SIGNALQUALITY, &tmp);
+ if (ret != 0)
+ return ret;
+
+ sig_qual = (tmp & STFM1000_NEAR_CHAN_AMPLITUDE_MASK) >>
+ STFM1000_NEAR_CHAN_AMPLITUDE_SHIFT;
+
+ if (sig_qual < stfm1000->adj_chan_th)
+ bypass_setting = 2;
+ }
+#endif
+ /* set filter settings */
+ ret = stfm1000_write_masked(STFM1000_INITIALIZATION1,
+ STFM1000_B2_BYPASS_FILT(bypass_setting),
+ STFM1000_B2_BYPASS_FILT_MASK);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x)))
+
+static int stfm1000_track_pilot(void)
+{
+ static const struct {
+ int delay;
+ uint32_t value;
+ } track_table[] = {
+ { .delay = 10, .value = 0x81b6 },
+ { .delay = 6, .value = 0x82a5 },
+ { .delay = 6, .value = 0x8395 },
+ { .delay = 8, .value = 0x8474 },
+ { .delay = 20, .value = 0x8535 },
+ { .delay = 50, .value = 0x8632 },
+ { .delay = 0, .value = 0x8810 },
+ };
+ int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(track_table); i++) {
+ ret = stfm1000_write(STFM1000_PILOTTRACKING, track_table[i].value);
+ if (ret != 0)
+ return ret;
+
+ if (i < ARRAY_SIZE(track_table) - 1) /* last one no delay */
+ sleep(track_table[i].delay * HZ / 1000);
+ }
+
+ return 0;
+}
+
+static int stfm1000_optimise_channel(void)
+{
+ int ret;
+
+ ret = stfm1000_set_bits(STFM1000_DATAPATH, STFM1000_DB_ACCEPT);
+ if (ret != 0)
+ return ret;
+
+ ret = stfm1000_write(STFM1000_PILOTTRACKING,
+ STFM1000_B2_PILOTTRACKING_EN |
+ STFM1000_B2_PILOTLPF_TIMECONSTANT(0x01) |
+ STFM1000_B2_PFDSCALE(0x0B) |
+ STFM1000_B2_PFDFILTER_SPEEDUP(0x06)); /* 0x000081B6 */
+ if (ret != 0)
+ return ret;
+
+ ret = stfm1000_set_channel_filter();
+ if (ret != 0)
+ return ret;
+#if 0
+ ret = SD_Look_For_Pilot(stfm1000);
+ if (ret != 0)
+ return ret;
+#endif
+// if (stfm1000->pilot_present) {
+ ret = stfm1000_track_pilot();
+ if (ret != 0)
+ return ret;
+// }
+
+ ret = stfm1000_clear_bits(STFM1000_DATAPATH, STFM1000_DB_ACCEPT);
+ if (ret != 0)
+ return ret;
+
+ return 0;
}
void stfm1000_init(void)
{
+ uint32_t val;
+
+ /* get revision id */
+ stfm1000_read(STFM1000_CHIPID, &val);
+ rev_id = val & 0xFF;
+
+ /* send TB2 init sequence */
+ stfm1000_write(STFM1000_REF, 0x00200000);
+ sleep(20 * HZ / 1000);
+ stfm1000_write(STFM1000_DATAPATH, 0x00010210);
+ stfm1000_write(STFM1000_TUNE1, 0x0004CF01);
+ stfm1000_write(STFM1000_SDNOMINAL, 0x1C5EBCF0);
+ stfm1000_write(STFM1000_PILOTTRACKING, 0x000001B6);
+ stfm1000_write(STFM1000_INITIALIZATION1, 0x9fb80008);
+ stfm1000_write(STFM1000_INITIALIZATION2, 0x8516e444 | STFM1000_DEEMPH_50_75B);
+ stfm1000_write(STFM1000_INITIALIZATION3, 0x1402190b);
+ stfm1000_write(STFM1000_INITIALIZATION4, 0x525bf052);
+ stfm1000_write(STFM1000_INITIALIZATION5, 0x1000d106);
+ stfm1000_write(STFM1000_INITIALIZATION6, 0x000062cb);
+ stfm1000_write(STFM1000_AGC_CONTROL1, 0x1BCB2202);
+ stfm1000_write(STFM1000_AGC_CONTROL2, 0x000020F0);
+ stfm1000_write(STFM1000_CLK1, 0x10000000);
+ stfm1000_write(STFM1000_CLK1, 0x20000000);
+ stfm1000_write(STFM1000_CLK1, 0x00000000);
+ stfm1000_write(STFM1000_CLK2, 0x7f000000);
+ stfm1000_write(STFM1000_REF, 0x00B8222D);
+ stfm1000_write(STFM1000_CLK1, 0x30000000);
+ stfm1000_write(STFM1000_CLK1, 0x30002000);
+ stfm1000_write(STFM1000_CLK1, 0x10002000);
+ stfm1000_write(STFM1000_LNA, 0x0D080009);
+ sleep(10 * HZ / 1000);
+ stfm1000_write(STFM1000_MIXFILT, 0x00008000);
+ stfm1000_write(STFM1000_MIXFILT, 0x00000000);
+ stfm1000_write(STFM1000_MIXFILT, 0x00007205);
+ stfm1000_write(STFM1000_ADC, 0x001B3282);
+ stfm1000_write(STFM1000_ATTENTION, 0x0000003F);
+
+ stfm1000_dp_enable(true);
+ stfm_dri_enable(true);
+}
+
+static void stfm1000_sleep(bool sleep)
+{
+ (void)sleep;
+ /* no implementation yet */
+}
+
+static int stfm1000_rssi(void)
+{
+ uint32_t rssi_dc_est;
+ int rssi_mantissa, rssi_exponent, rssi_decoded;
+ int prssi;
+ int rssi_log;
+
+ stfm1000_read(STFM1000_RSSI_TONE, &rssi_dc_est);
+
+ rssi_mantissa = (rssi_dc_est & 0xffe0) >> 5; /* 11Msb */
+ rssi_exponent = rssi_dc_est & 0x001f; /* 5 lsb */
+ rssi_decoded = (uint32_t)rssi_mantissa << rssi_exponent;
+
+ /* Convert Rsst to 10log(Rssi) */
+ for (prssi = 20; prssi > 0; prssi--)
+ if (rssi_decoded >= (1 << prssi))
+ break;
+
+ rssi_log = (3 * rssi_decoded >> prssi) + (3 * prssi - 3);
+
+ /* clamp to positive */
+ if (rssi_log < 0)
+ rssi_log = 0;
+
+ /* Compensate for errors in truncation/approximation by adding 1 */
+ rssi_log++;
+
+ return rssi_log;
+}
+
+static bool stfm1000_tuned(void)
+{
+ uint32_t tmp;
+ int pilot;
+
+ /* get pilot */
+ stfm1000_read(STFM1000_PILOTCORRECTION, &tmp);
+ pilot = (tmp & STFM1000_PILOTEST_TB2_MASK) >> STFM1000_PILOTEST_TB2_SHIFT;
+
+ /* check pilot and signal strength */
+ return (pilot >= 0x1E) && (pilot < 0x80) && (stfm1000_rssi() > 28);
}
int stfm1000_set(int setting, int value)
{
- (void) setting;
- (void) value;
- return -1;
+ int val = 0;
+
+ switch (setting) {
+ case RADIO_SLEEP:
+ stfm1000_sleep(value);
+ break;
+
+ case RADIO_FREQUENCY:
+ stfm1000_set_frequency(value / 1000);
+ stfm1000_optimise_channel();
+ imx233_dri_enable(true);
+ break;
+
+ case RADIO_SCAN_FREQUENCY:
+ stfm1000_set_frequency(value / 1000);
+ val = stfm1000_tuned();
+ break;
+
+ case RADIO_MUTE:
+ /* no implementation yet */
+ break;
+
+ case RADIO_REGION:
+ stfm1000_set_region(value);
+ break;
+
+ case RADIO_FORCE_MONO:
+ /* no implementation yet */
+ break;
+
+ default:
+ val = -1;
+ break;
+ }
+
+ return val;
}
int stfm1000_get(int setting)
{
- (void) setting;
- return -1;
-}
\ No newline at end of file
+ int val = -1; /* default for unsupported query */
+
+ switch (setting) {
+
+ case RADIO_PRESENT:
+ val = true;
+ break;
+
+ case RADIO_TUNED:
+ val = stfm1000_tuned();
+ break;
+
+ case RADIO_STEREO:
+ val = 0;
+ break;
+#if 1
+ case RADIO_RSSI:
+ val = stfm1000_rssi();
+ break;
+
+ case RADIO_RSSI_MIN:
+ val = 0;
+ break;
+
+ case RADIO_RSSI_MAX:
+ val = 70;
+ break;
+#endif
+ }
+
+ return val;
+}
diff --git a/firmware/export/stfm1000.h b/firmware/export/stfm1000.h
index 6c01d63..62a1dd9 100644
--- a/firmware/export/stfm1000.h
+++ b/firmware/export/stfm1000.h
@@ -31,6 +31,11 @@
struct stfm1000_dbg_info
{
+ uint32_t tune1;
+ uint32_t sdnominal;
+ uint32_t pilottracking;
+ uint32_t rssi_tone;
+ uint32_t pilotcorrection;
uint32_t chipid;
};
diff --git a/firmware/target/arm/imx233/creative-zenxfi2/audio-zenxfi2.c b/firmware/target/arm/imx233/creative-zenxfi2/audio-zenxfi2.c
index 810f1c1..7d913a9 100644
--- a/firmware/target/arm/imx233/creative-zenxfi2/audio-zenxfi2.c
+++ b/firmware/target/arm/imx233/creative-zenxfi2/audio-zenxfi2.c
@@ -31,7 +31,7 @@ static int output_source = AUDIO_SRC_PLAYBACK;
static void select_audio_path(void)
{
- if(input_source == AUDIO_SRC_PLAYBACK)
+ if(input_source == AUDIO_SRC_PLAYBACK || true)
imx233_audioout_select_hp_input(false);
else
imx233_audioout_select_hp_input(true);
diff --git a/firmware/target/arm/imx233/debug-imx233.c b/firmware/target/arm/imx233/debug-imx233.c
index c170139..b55a0c2 100644
--- a/firmware/target/arm/imx233/debug-imx233.c
+++ b/firmware/target/arm/imx233/debug-imx233.c
@@ -32,6 +32,7 @@
#include "rtc-imx233.h"
#include "dcp-imx233.h"
#include "pinctrl-imx233.h"
+#include "dri-imx233.h"
#include "string.h"
#define DEBUG_CANCEL BUTTON_BACK
@@ -46,6 +47,7 @@ static struct
{ "dac", APB_AUDIO_DAC },
{ "ssp1", APB_SSP(1) },
{ "ssp2", APB_SSP(2) },
+ { "dri", APB_DRI },
};
static struct
@@ -537,12 +539,42 @@ bool dbg_hw_info_pinctrl(void)
}
}
+bool dbg_hw_info_dri(void)
+{
+ lcd_setfont(FONT_SYSFIXED);
+
+ while(1)
+ {
+ int button = get_action(CONTEXT_STD, HZ / 10);
+ switch(button)
+ {
+ case ACTION_STD_NEXT:
+ case ACTION_STD_PREV:
+ case ACTION_STD_OK:
+ case ACTION_STD_MENU:
+ lcd_setfont(FONT_UI);
+ return true;
+ case ACTION_STD_CANCEL:
+ lcd_setfont(FONT_UI);
+ return false;
+ }
+
+ lcd_clear_display();
+ struct imx233_dri_info_t info = imx233_dri_get_info();
+ lcd_putsf(0, 0, "DRI");
+ lcd_putsf(0, 1, "run: %d", info.running);
+ lcd_putsf(0, 2, "inputs: %d", info.inputs_enabled);
+ lcd_update();
+ yield();
+ }
+}
+
bool dbg_hw_info(void)
{
return dbg_hw_info_clkctrl() && dbg_hw_info_dma() && dbg_hw_info_adc() &&
dbg_hw_info_power() && dbg_hw_info_powermgmt() && dbg_hw_info_rtc() &&
dbg_hw_info_dcp() && dbg_hw_info_pinctrl() && dbg_hw_info_icoll() &&
- dbg_hw_target_info();
+ dbg_hw_info_dri() && dbg_hw_target_info();
}
bool dbg_ports(void)
diff --git a/firmware/target/arm/imx233/dma-imx233.h b/firmware/target/arm/imx233/dma-imx233.h
index ee836c2..10a0d1e 100644
--- a/firmware/target/arm/imx233/dma-imx233.h
+++ b/firmware/target/arm/imx233/dma-imx233.h
@@ -79,6 +79,7 @@
#define HW_APBX_AUDIO_ADC 0
#define HW_APBX_AUDIO_DAC 1
#define HW_APBX_I2C 3
+#define HW_APBX_DRI 5
#define HW_APBX_BASE 0x80024000
@@ -166,6 +167,7 @@ struct imx233_dma_info_t
#define APB_AUDIO_DAC APBX_DMA_CHANNEL(HW_APBX_AUDIO_DAC)
#define APB_I2C APBX_DMA_CHANNEL(HW_APBX_I2C)
#define APB_NAND(dev) APBH_DMA_CHANNEL(HW_APBH_NAND(dev))
+#define APB_DRI APBX_DMA_CHANNEL(HW_APBX_DRI)
#define HW_APB_CHx_CMD__COMMAND_BM 0x3
#define HW_APB_CHx_CMD__COMMAND__NO_XFER 0
diff --git a/firmware/target/arm/imx233/dri-imx233.c b/firmware/target/arm/imx233/dri-imx233.c
new file mode 100644
index 0000000..08aeb9b
--- /dev/null
+++ b/firmware/target/arm/imx233/dri-imx233.c
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "dri-imx233.h"
+#include "clkctrl-imx233.h"
+#include "system-target.h"
+#include "dma-imx233.h"
+#include "icoll-imx233.h"
+#include "string.h"
+#include "pcm.h"
+#include "pcm_sampr.h"
+
+struct dri_dma_command_t
+{
+ struct apb_dma_command_t dma;
+ /* padded to next multiple of cache line size (32 bytes) */
+ uint32_t pad[5];
+} __attribute__((packed)) CACHEALIGN_ATTR;
+
+__ENSURE_STRUCT_CACHE_FRIENDLY(struct dri_dma_command_t)
+
+static struct dri_dma_command_t dri_dma;
+
+#define DRI_BUFFER_SIZE 4000
+#define DAC_BUFFER_SIZE 2000
+
+static uint16_t dri_buffer[DRI_BUFFER_SIZE];
+static uint16_t dac_buffer[DAC_BUFFER_SIZE];
+
+void imx233_dri_init(void)
+{
+ imx233_reset_block(&HW_DRI_CTRL);
+}
+
+void dri_pcm_cb(const void **start, size_t *size)
+{
+ *start = dac_buffer;
+ *size = DAC_BUFFER_SIZE;
+}
+
+void INT_DRI_DMA(void)
+{
+ for(size_t i = 0, j = 0; i< DRI_BUFFER_SIZE && j < DAC_BUFFER_SIZE; i += 4, j += 2)
+ {
+ dac_buffer[j] = dri_buffer[i] + dri_buffer[i + 1];
+ dac_buffer[j + 1] = dri_buffer[i] - dri_buffer[i + 1];
+ }
+
+ imx233_dma_clear_channel_interrupt(APB_DRI);
+}
+
+void imx233_dri_enable(bool en)
+{
+ if(en)
+ {
+ imx233_reset_block(&HW_DRI_CTRL);
+ imx233_clkctrl_enable_xtal(XTAL_DRI, true);
+ pcm_set_frequency(FREQ_44);
+ pcm_apply_settings();
+ pcm_play_data(dri_pcm_cb, NULL, dac_buffer, DAC_BUFFER_SIZE);
+ pcm_play_pause(true);
+
+ imx233_dma_reset_channel(APB_DRI);
+ imx233_icoll_enable_interrupt(INT_SRC_DRI_DMA, true);
+ imx233_dma_enable_channel_interrupt(APB_DRI, true);
+
+ dri_dma.dma.next = &dri_dma.dma;
+ dri_dma.dma.buffer = (void *)dri_buffer;
+ dri_dma.dma.cmd = HW_APB_CHx_CMD__COMMAND__WRITE |
+ DRI_BUFFER_SIZE << HW_APB_CHx_CMD__XFER_COUNT_BP |
+ HW_APB_CHx_CMD__IRQONCMPLT |
+ HW_APB_CHx_CMD__CHAIN;
+ /* dma subsystem will make sure cached stuff is written to memory */
+ imx233_dma_start_command(APB_DRI, &dri_dma.dma);
+
+ __REG_SET(HW_DRI_CTRL) = HW_DRI_CTRL__ENABLE_INPUTS | HW_DRI_CTRL__RUN |
+ HW_DRI_CTRL__REACQUIRE_PHASE;
+ }
+ else
+ {
+ pcm_play_stop();
+ imx233_dma_enable_channel_interrupt(APB_DRI, false);
+ imx233_icoll_enable_interrupt(INT_SRC_DRI_DMA, false);
+ __REG_CLR(HW_DRI_CTRL) = HW_DRI_CTRL__ENABLE_INPUTS | HW_DRI_CTRL__RUN;
+ imx233_clkctrl_enable_xtal(XTAL_DRI, false);
+ }
+}
+
+struct imx233_dri_info_t imx233_dri_get_info(void)
+{
+ struct imx233_dri_info_t info;
+ memset(&info, 0, sizeof(info));
+
+ info.running = !!(HW_DRI_CTRL & HW_DRI_CTRL__RUN);
+ info.inputs_enabled = !!(HW_DRI_CTRL & HW_DRI_CTRL__ENABLE_INPUTS);
+
+ return info;
+}
\ No newline at end of file
diff --git a/firmware/target/arm/imx233/dri-imx233.h b/firmware/target/arm/imx233/dri-imx233.h
new file mode 100644
index 0000000..6914baa
--- /dev/null
+++ b/firmware/target/arm/imx233/dri-imx233.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __dri_imx233__
+#define __dri_imx233__
+
+#include "config.h"
+#include "cpu.h"
+#include "system.h"
+
+#define HW_DRI_BASE 0x80074000
+
+#define HW_DRI_CTRL (*(volatile uint32_t *)(HW_DRI_BASE + 0x0))
+#define HW_DRI_CTRL__RUN (1 << 0)
+#define HW_DRI_CTRL__REACQUIRE_PHASE (1 << 15)
+#define HW_DRI_CTRL__ENABLE_INPUTS (1 << 29)
+
+#define HW_DRI_TIMING (*(volatile uint32_t *)(HW_DRI_BASE + 0x10))
+#define HW_DRI_TIMING__GAP_DETECTION_INTERVAL_BP 0
+#define HW_DRI_TIMING__GAP_DETECTION_INTERVAL_BM 0xff
+#define HW_DRI_TIMING__PILOT_REP_RATE_BP 16
+#define HW_DRI_TIMING__PILOT_REP_RATE_BM (0xf << 16)
+
+#define HW_DRI_STAT (*(volatile uint32_t *)(HW_DRI_BASE + 0x20))
+
+#define HW_DRI_DATA (*(volatile uint32_t *)(HW_DRI_BASE + 0x30))
+
+#define HW_DRI_DEBUG0 (*(volatile uint32_t *)(HW_DRI_BASE + 0x40))
+
+#define HW_DRI_DEBUG1 (*(volatile uint32_t *)(HW_DRI_BASE + 0x50))
+
+struct imx233_dri_info_t
+{
+ bool running;
+ bool inputs_enabled;
+};
+
+void imx233_dri_init(void);
+void imx233_dri_enable(bool en);
+struct imx233_dri_info_t imx233_dri_get_info(void);
+
+#endif /* __dri_imx233__ */
diff --git a/firmware/target/arm/imx233/icoll-imx233.c b/firmware/target/arm/imx233/icoll-imx233.c
index 4e0d525..9a0e1da 100644
--- a/firmware/target/arm/imx233/icoll-imx233.c
+++ b/firmware/target/arm/imx233/icoll-imx233.c
@@ -61,6 +61,8 @@ default_interrupt(INT_ADC_DMA);
default_interrupt(INT_ADC_ERROR);
default_interrupt(INT_DCP);
default_interrupt(INT_TOUCH_DETECT);
+default_interrupt(INT_DRI_DMA);
+default_interrupt(INT_DRI_ATTENTION);
void INT_RTC_1MSEC(void);
@@ -100,6 +102,8 @@ static isr_t isr_table[INT_SRC_NR_SOURCES] =
[INT_SRC_DCP] = INT_DCP,
[INT_SRC_TOUCH_DETECT] = INT_TOUCH_DETECT,
[INT_SRC_RTC_1MSEC] = INT_RTC_1MSEC,
+ [INT_SRC_DRI_DMA] = INT_DRI_DMA,
+ [INT_SRC_DRI_ATTENTION] = INT_DRI_ATTENTION,
};
#define IRQ_STORM_DELAY 1000 /* ms */
diff --git a/firmware/target/arm/imx233/icoll-imx233.h b/firmware/target/arm/imx233/icoll-imx233.h
index d1bf8a1..7abb0ac 100644
--- a/firmware/target/arm/imx233/icoll-imx233.h
+++ b/firmware/target/arm/imx233/icoll-imx233.h
@@ -65,6 +65,8 @@
#define INT_SRC_LCDIF_DMA 45
#define INT_SRC_LCDIF_ERROR 46
#define INT_SRC_RTC_1MSEC 48
+#define INT_SRC_DRI_DMA 49
+#define INT_SRC_DRI_ATTENTION 50
#define INT_SRC_DCP 54
#define INT_SRC_NR_SOURCES 66
diff --git a/tools/configure b/tools/configure
index 4d3d746..da52a10 100755
--- a/tools/configure
+++ b/tools/configure
@@ -2211,7 +2211,7 @@ fi
output="rockbox.creative"
bootoutput="bootloader-zenxfi2.creative"
appextra="gui:recorder:radio"
- plugins="yes"
+ plugins=""
swcodec="yes"
toolset=$scramblebitmaptools
t_cpu="arm"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.