At Thu, 13 Sep 2012 18:15:55 -0700, Ian Minett wrote:
From: Ian Minett ian_minett@creativelabs.com
Give a bit more description what this patch really does and also what it doesn't. This just implements the firmware loading, but the new DSP functionality itself isn't used yet, right?
Signed-off-by: Ian Minett ian_minett@creativelabs.com
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 8ea3348..11f5910 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -48,9 +48,6 @@ #define WIDGET_CHIP_CTRL 0x15 #define WIDGET_DSP_CTRL 0x16
-#define WUH_MEM_CONNID 10 -#define DSP_MEM_CONNID 16
#define MEM_CONNID_MICIN1 3 #define MEM_CONNID_MICIN2 5 #define MEM_CONNID_MICOUT1 12 @@ -352,6 +349,25 @@ static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, #define add_in_mono_volume(codec, nid, pfx, chan) \ _add_volume(codec, nid, pfx, chan, 1)
+enum dsp_download_state {
- DSP_DOWNLOAD_FAILED = -1,
- DSP_DOWNLOAD_INIT = 0,
- DSP_DOWNLOADING = 1,
- DSP_DOWNLOADED = 2
+};
+struct hda_stream_format {
- unsigned int sample_rate;
- unsigned short valid_bits_per_sample;
- unsigned short container_size;
- unsigned short number_channels;
+};
+/* retrieve parameters from hda format */ +#define get_hdafmt_chs(fmt) (fmt & 0xf) +#define get_hdafmt_bits(fmt) ((fmt >> 4) & 0x7) +#define get_hdafmt_rate(fmt) ((fmt >> 8) & 0x7f) +#define get_hdafmt_type(fmt) ((fmt >> 15) & 0x1)
This can be well in hda_codec.h. But it's fine to define here for now...
/*
- CA0132 specific
@@ -371,11 +387,55 @@ struct ca0132_spec { long curr_hp_switch; long curr_hp_volume[2]; long curr_speaker_switch;
- struct mutex chipio_mutex; const char *input_labels[AUTO_PIN_LAST]; struct hda_pcm pcm_rec[2]; /* PCM information */
- /* chip access */
- struct mutex chipio_mutex; /* chip access mutex */
- u32 curr_chip_addx;
- /* DSP download related */
- enum dsp_download_state dsp_state;
- unsigned int dsp_stream_id;
- unsigned int wait_scp;
- unsigned int wait_scp_header;
- unsigned int wait_num_data;
- unsigned int scp_resp_header;
- unsigned int scp_resp_data[4];
- unsigned int scp_resp_count;
};
+/*
- CA0132 codec access
- */
+unsigned int codec_send_command(struct hda_codec *codec, hda_nid_t nid,
unsigned int verb, unsigned int parm, unsigned int *res)
+{
- unsigned int response;
- response = snd_hda_codec_read(codec, nid, 0, verb, parm);
- *res = response;
- return ((response == -1) ? -1 : 0);
+}
+static int codec_set_converter_format(struct hda_codec *codec, hda_nid_t nid,
unsigned short converter_format, unsigned int *res)
+{
- return codec_send_command(codec, nid, VENDOR_CHIPIO_STREAM_FORMAT,
converter_format & 0xffff, res);
+}
+static int codec_set_converter_stream_channel(struct hda_codec *codec,
hda_nid_t nid, unsigned char stream,
unsigned char channel, unsigned int *res)
+{
- unsigned char converter_stream_channel = 0;
- converter_stream_channel = (stream << 4) | (channel & 0x0f);
- return codec_send_command(codec, nid, AC_VERB_SET_CHANNEL_STREAMID,
converter_stream_channel, res);
+}
/* Chip access helper function */ static int chipio_send(struct hda_codec *codec, unsigned int reg, @@ -415,6 +475,30 @@ static int chipio_write_address(struct hda_codec *codec, return res; }
+static int chipio_write_addx(struct hda_codec *codec, u32 chip_addx) +{
- struct ca0132_spec *spec = codec->spec;
- int status;
- if (spec->curr_chip_addx == chip_addx)
return 0;
- /* send low 16 bits of the address */
- status = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW,
chip_addx & 0xffff);
- if (status < 0)
return status;
- /* send high 16 bits of the address */
- status = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_HIGH,
chip_addx >> 16);
- spec->curr_chip_addx = (status < 0) ? ~0UL : chip_addx;
- return status;
+}
/*
- Write data through the vendor widget -- NOT protected by the Mutex!
*/ @@ -435,6 +519,24 @@ static int chipio_write_data(struct hda_codec *codec, unsigned int data) return res; }
+static int chipio_write_data_multiple(struct hda_codec *codec,
const u32 *data,
unsigned int count)
+{
- int status = 0;
- if (data == NULL) {
snd_printdd(KERN_ERR "chipio_write_data null ptr");
return -EINVAL;
- }
- while ((count-- != 0) && (status == 0))
status = chipio_write_data(codec, *data++);
- return status;
+}
/*
- Read data through the vendor widget -- NOT protected by the Mutex!
*/ @@ -486,6 +588,26 @@ exit: return err; }
+static int chipio_write_multiple(struct hda_codec *codec,
u32 chip_addx,
const u32 *data,
unsigned int count)
+{
- struct ca0132_spec *spec = codec->spec;
- int status;
- mutex_lock(&spec->chipio_mutex);
- status = chipio_write_addx(codec, chip_addx);
- if (status < 0)
goto error;
- status = chipio_write_data_multiple(codec, data, count);
+error:
- mutex_unlock(&spec->chipio_mutex);
- return status;
+}
/*
- Read the given address through the chip I/O widget
- protected by the Mutex
@@ -512,6 +634,1425 @@ exit: return err; }
+static void chipio_set_control_flag(struct hda_codec *codec,
enum control_flag_id flag_id,
bool flag_state)
+{
- unsigned int val;
- unsigned int flag_bit;
- flag_bit = (flag_state ? 1 : 0);
- val = (flag_bit << 7) | (flag_id);
- snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_FLAG_SET, val);
+}
+static void chipio_set_control_param(struct hda_codec *codec,
enum control_param_id param_id, int param_val)
+{
- struct ca0132_spec *spec = codec->spec;
- int val;
- if ((param_id < 32) && (param_val < 8)) {
val = (param_val << 5) | (param_id);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_SET, val);
- } else {
mutex_lock(&spec->chipio_mutex);
if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) {
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_EX_ID_SET,
param_id);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_EX_VALUE_SET,
param_val);
}
mutex_unlock(&spec->chipio_mutex);
- }
+}
+static void chipio_set_conn_rate(struct hda_codec *codec,
int connid, enum ca0132_sample_rate rate)
+{
- chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_ID, connid);
- chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_SAMPLE_RATE,
rate);
+}
+static void chipio_enable_clocks(struct hda_codec *codec) +{
- struct ca0132_spec *spec = codec->spec;
- mutex_lock(&spec->chipio_mutex);
- snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_8051_ADDRESS_LOW, 0);
- snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PLL_PMU_WRITE, 0xff);
- snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_8051_ADDRESS_LOW, 5);
- snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PLL_PMU_WRITE, 0x0b);
- snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_8051_ADDRESS_LOW, 6);
- snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PLL_PMU_WRITE, 0xff);
- mutex_unlock(&spec->chipio_mutex);
+}
+/*
- CA0132 DSP IO stuffs
- */
+static int dspio_send(struct hda_codec *codec, unsigned int reg,
unsigned int data)
+{
- unsigned int res;
- int retry = 50;
- /* send bits of data specified by reg to dsp */
- do {
res = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, reg, data);
if ((res >= 0) && (res != VENDOR_STATUS_DSPIO_BUSY))
return res;
- } while (--retry);
- return -EIO;
+}
+static void dspio_write_wait(struct hda_codec *codec) +{
- int cur_val, prv_val;
- int retry = 50;
- cur_val = 0;
- do {
prv_val = cur_val;
msleep(20);
dspio_send(codec, VENDOR_DSPIO_SCP_POST_COUNT_QUERY, 1);
dspio_send(codec, VENDOR_DSPIO_STATUS, 0);
cur_val = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
VENDOR_DSPIO_SCP_READ_COUNT, 0);
- } while (cur_val && (cur_val == prv_val) && --retry);
+}
+static int dspio_write(struct hda_codec *codec, unsigned int scp_data) +{
- struct ca0132_spec *spec = codec->spec;
- int status;
- dspio_write_wait(codec);
- mutex_lock(&spec->chipio_mutex);
- status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_LOW,
scp_data & 0xffff);
- if (status < 0)
goto error;
- status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_HIGH,
scp_data >> 16);
- if (status < 0)
goto error;
- /* OK, now check if the write itself has executed*/
- status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
VENDOR_DSPIO_STATUS, 0);
+error:
- mutex_unlock(&spec->chipio_mutex);
- return (status == VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL) ?
-EIO : 0;
+}
+static int dspio_write_multiple(struct hda_codec *codec,
unsigned int *buffer, unsigned int size)
+{
- int status = 0;
- unsigned int count;
- if ((buffer == NULL))
return -EINVAL;
- count = 0;
- while (count < size) {
status = dspio_write(codec, *buffer++);
if (status != 0)
break;
count++;
- }
- return status;
+}
+static inline unsigned int +make_scp_header(unsigned int target_id, unsigned int source_id,
unsigned int get_flag, unsigned int req,
unsigned int device_flag, unsigned int resp_flag,
unsigned int error_flag, unsigned int data_size)
+{
- unsigned int header = 0;
- header = (data_size & 0x1f) << 27;
- header |= (error_flag & 0x01) << 26;
- header |= (resp_flag & 0x01) << 25;
- header |= (device_flag & 0x01) << 24;
- header |= (req & 0x7f) << 17;
- header |= (get_flag & 0x01) << 16;
- header |= (source_id & 0xff) << 8;
- header |= target_id & 0xff;
- return header;
+}
+static inline void +extract_scp_header(unsigned int header,
unsigned int *target_id, unsigned int *source_id,
unsigned int *get_flag, unsigned int *req,
unsigned int *device_flag, unsigned int *resp_flag,
unsigned int *error_flag, unsigned int *data_size)
+{
- if (data_size)
*data_size = (header >> 27) & 0x1f;
- if (error_flag)
*error_flag = (header >> 26) & 0x01;
- if (resp_flag)
*resp_flag = (header >> 25) & 0x01;
- if (device_flag)
*device_flag = (header >> 24) & 0x01;
- if (req)
*req = (header >> 17) & 0x7f;
- if (get_flag)
*get_flag = (header >> 16) & 0x01;
- if (source_id)
*source_id = (header >> 8) & 0xff;
- if (target_id)
*target_id = header & 0xff;
+}
+#define SCP_MAX_DATA_WORDS (16)
+/* Structure to contain any SCP message */ +struct scp_msg {
- unsigned int hdr;
- unsigned int data[SCP_MAX_DATA_WORDS];
+};
+static int dspio_send_scp_message(struct hda_codec *codec,
unsigned char *send_buf,
unsigned int send_buf_size,
unsigned char *return_buf,
unsigned int return_buf_size,
unsigned int *bytes_returned)
+{
- struct ca0132_spec *spec = codec->spec;
- int retry;
- int status = -1;
- unsigned int scp_send_size = 0;
- unsigned int total_size;
- bool waiting_for_resp = false;
- unsigned int header;
- struct scp_msg *ret_msg;
- unsigned int resp_src_id, resp_target_id;
- unsigned int data_size, src_id, target_id, get_flag, device_flag;
- if (bytes_returned)
*bytes_returned = 0;
- /* get scp header from buffer */
- header = *((unsigned int *)send_buf);
This is not quite portable. The HD-audio itself might be implemented in big-endian machines, too.
Or, this might be more about struct scp_msg definition. What is the expectation from the hardware? Does the codec expect 32bit little endian values? Then you'd need to convert data explicitly when the architecture is big-endian.
(snip)
static int ca0132_init(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; int i;
- ca0132_download_dsp(codec);
As I mentioned earlier, you cannot implement the DSP loading code unconditionally. User might not have a DSP firmware but only updated the kernel. Then it gets broken.
The DSP loading code (and the relevant stuff) must be protected via ifdef CONFIG_SND_HDA_DSP_LOADER. And yet, it wouldn't be bad to have a module option to control the firmware loading as wel.
Takashi