Exemple #1
0
/* K8 systems have some devices (typically in the builtin northbridge)
   that are only accessible using type1
   Normally this can be expressed in the MCFG by not listing them
   and assigning suitable _SEGs, but this isn't implemented in some BIOS.
   Instead try to discover all devices on bus 0 that are unreachable using MM
   and fallback for them. */
static __init void unreachable_devices(void)
{
	int i, k;
	unsigned long flags;

	for (k = 0; k < MAX_CHECK_BUS; k++) {
		for (i = 0; i < 32; i++) {
			u32 val1;
			u32 addr;

			pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1);
			if (val1 == 0xffffffff)
				continue;

			/* Locking probably not needed, but safer */
			spin_lock_irqsave(&pci_config_lock, flags);
			addr = get_base_addr(0, k, PCI_DEVFN(i, 0));
			if (addr != 0)
				pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0));
			if (addr == 0 ||
			    readl((u32 __iomem *)mmcfg_virt_addr) != val1) {
				set_bit(i + 32*k, fallback_slots);
				printk(KERN_NOTICE
			"PCI: No mmconfig possible on %x:%x\n", k, i);
			}
			spin_unlock_irqrestore(&pci_config_lock, flags);
		}
	}
}
static void mi2s_release(struct mi2s_state *mi2s, uint8_t dev_id)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	if (!IS_ERR(baddr))
		writel(MI2S_RESET__MI2S_RESET__ACTIVE,
		baddr + MI2S_RESET_OFFSET);
}
Exemple #3
0
static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
			  unsigned int devfn, int reg, int len, u32 *value)
{
	unsigned long flags;
	u32 base;

	if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
err:		*value = -1;
		return -EINVAL;
	}

	base = get_base_addr(seg, bus, devfn);
	if (!base)
		goto err;

	raw_spin_lock_irqsave(&pci_config_lock, flags);

	pci_exp_set_dev_base(base, bus, devfn);

	switch (len) {
	case 1:
		*value = mmio_config_readb(mmcfg_virt_addr + reg);
		break;
	case 2:
		*value = mmio_config_readw(mmcfg_virt_addr + reg);
		break;
	case 4:
		*value = mmio_config_readl(mmcfg_virt_addr + reg);
		break;
	}
	raw_spin_unlock_irqrestore(&pci_config_lock, flags);

	return 0;
}
Exemple #4
0
static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
			   unsigned int devfn, int reg, int len, u32 value)
{
	unsigned long flags;
	u32 base;

	if ((bus > 255) || (devfn > 255) || (reg > 4095))
		return -EINVAL;

	base = get_base_addr(seg, bus, devfn);
	if (!base)
		return -EINVAL;

	raw_spin_lock_irqsave(&pci_config_lock, flags);

	pci_exp_set_dev_base(base, bus, devfn);

	switch (len) {
	case 1:
		mmio_config_writeb(mmcfg_virt_addr + reg, value);
		break;
	case 2:
		mmio_config_writew(mmcfg_virt_addr + reg, value);
		break;
	case 4:
		mmio_config_writel(mmcfg_virt_addr + reg, value);
		break;
	}
	raw_spin_unlock_irqrestore(&pci_config_lock, flags);

	return 0;
}
static void mi2s_set_output_num_channels(struct mi2s_state *mi2s,
	uint8_t dev_id, uint8_t channels)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	uint32_t val;
	if (!IS_ERR(baddr)) {
		val = readl(baddr + MI2S_TX_MODE_OFFSET);
		if (channels == MI2S_CHAN_MONO_RAW) {
			val = (val &
			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_BMSK)) |
			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__MONO_SAMPLE <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
			(MI2S_TX_MODE__MI2S_TX_CODEC_16_MONO_MODE__RAW <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_SHFT));
		} else if (channels == MI2S_CHAN_MONO_PACKED) {
			val = (val &
			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_BMSK)) |
			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__MONO_SAMPLE <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
			(MI2S_TX_MODE__MI2S_TX_CODEC_16_MONO_MODE__PACKED <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_P_MONO_SHFT));
		} else if (channels == MI2S_CHAN_STEREO) {
			val = (val &
			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK)) |
			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
			(MI2S_TX_MODE__MI2S_TX_CH_TYPE__2_CHANNEL <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT));
		} else if (channels == MI2S_CHAN_4CHANNELS) {
			val = (val &
			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK)) |
			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
			(MI2S_TX_MODE__MI2S_TX_CH_TYPE__4_CHANNEL <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT));
		} else if (channels == MI2S_CHAN_6CHANNELS) {
			val = (val &
			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK)) |
			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
			(MI2S_TX_MODE__MI2S_TX_CH_TYPE__6_CHANNEL <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT));
		} else if (channels == MI2S_CHAN_8CHANNELS) {
			val = (val &
			~(HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_BMSK |
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_BMSK)) |
			((MI2S_TX_MODE__MI2S_TX_STEREO_MODE__STEREO_SAMPLE <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_STEREO_MODE_SHFT) |
			(MI2S_TX_MODE__MI2S_TX_CH_TYPE__8_CHANNEL <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_CH_TYPE_SHFT));
		}
		writel(val, baddr + MI2S_TX_MODE_OFFSET);
	}
}
Exemple #6
0
void hp80_io_slot_device::install_read_write_handlers(address_space& space)
{
	hp80_io_card_device *card = downcast<hp80_io_card_device*>(get_card_device());

	if (card != nullptr) {
		card->install_read_write_handlers(space , get_base_addr());
	}
}
static void mi2s_set_sd(struct mi2s_state *mi2s, uint8_t dev_id, uint8_t sd_map)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	uint32_t val;
	if (!IS_ERR(baddr)) {
		val = readl(baddr + MI2S_MODE_OFFSET) &
			~(MI2S_SD_N_EN_MASK | MI2S_TX_RX_N_MASK);
		writel(val | sd_map, baddr + MI2S_MODE_OFFSET);
	}
}
static void mi2s_set_output_4ch_map(struct mi2s_state *mi2s, uint8_t dev_id,
	bool high_low)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	uint32_t val;
	if (!IS_ERR(baddr)) {
		val = readl(baddr + MI2S_TX_MODE_OFFSET);
		val = (val & ~HWIO_AUDIO1_MI2S_TX_MODE_MI2S_4_0_CH_MAP_BMSK) |
			(high_low <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_4_0_CH_MAP_SHFT);
		writel(val, baddr + MI2S_TX_MODE_OFFSET);
	}
}
static void mi2s_set_output_clk_synch(struct mi2s_state *mi2s, uint8_t dev_id)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	uint32_t val;

	if (!IS_ERR(baddr)) {
		val = readl(baddr + MI2S_TX_MODE_OFFSET);
		writel(((val &
		~HWIO_AUDIO1_MI2S_TX_MODE_MI2S_TX_DMA_ACK_SYNCH_EN_BMSK) |
		MI2S_TX_MODE__MI2S_TX_DMA_ACK_SYNCH_EN__SYNC_ENABLE),
		baddr + MI2S_TX_MODE_OFFSET);
	}
}
static void mi2s_set_input_sd_line(struct mi2s_state *mi2s, uint8_t dev_id,
	uint8_t sd_line)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	uint32_t val;

	if (!IS_ERR(baddr)) {
		val = readl(baddr + MI2S_RX_MODE_OFFSET);
		if (sd_line < 4) {
			val = (val &
			~HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_I2S_LINE_BMSK) |
			(sd_line <<
			HWIO_AUDIO1_MI2S_RX_MODE_MI2S_RX_I2S_LINE_SHFT);
			writel(val, baddr + MI2S_RX_MODE_OFFSET);
		}
	}
}
static void mi2s_set_output_2ch_map(struct mi2s_state *mi2s, uint8_t dev_id,
	uint8_t sd_line)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	uint32_t val;

	if (!IS_ERR(baddr)) {
		val = readl(baddr + MI2S_TX_MODE_OFFSET);
		if (sd_line < 4) {
			val = (val &
			~HWIO_AUDIO1_MI2S_TX_MODE_MI2S_2_0_CH_MAP_BMSK) |
			(sd_line <<
			HWIO_AUDIO1_MI2S_TX_MODE_MI2S_2_0_CH_MAP_SHFT);
			writel(val, baddr + MI2S_TX_MODE_OFFSET);
		}
	}
}
Exemple #12
0
uint8_t l_to_p(const logical_addr* logical, int* tlb_hit){
	short find = 0;
	int i;
	for(i = 0; i < last_entry; i++){
		if(tlb[i].page_index == logical->page_number){
			tlb[i].access++;
			find = 1;
			if(tlb_hit) *tlb_hit = 1;
			return tlb[i].frame_index;
		}
	}
	if(!find){
		if(tlb_hit) *tlb_hit = 0;
		uint8_t frame = get_base_addr(logical->page_number);
		add_tlb_entry(logical->page_number, frame);
		return frame;
	}
	return 0;
}
/* Set who control aux pcm : adsp or MSM */
void aux_codec_adsp_codec_ctl_en(bool msm_adsp_en)
{
	void __iomem *baddr = get_base_addr(&the_aux_pcm_state);
	uint32_t val;

	if (!IS_ERR(baddr)) {
		val = readl(baddr + AUX_CODEC_CTL_OFFSET);
		if (msm_adsp_en) { /* adsp */
			writel(
			((val & ~AUX_CODEC_CTL_ADSP_CODEC_CTL_EN_BMSK) |
			AUX_CODEC_CTL__ADSP_CODEC_CTL_EN__ADSP_V),
			baddr + AUX_CODEC_CTL_OFFSET);
		} else { /* MSM */
			writel(
			((val & ~AUX_CODEC_CTL_ADSP_CODEC_CTL_EN_BMSK) |
			AUX_CODEC_CTL__ADSP_CODEC_CTL_EN__MSM_V),
			baddr + AUX_CODEC_CTL_OFFSET);
		}
	}

}
static void mi2s_master(struct mi2s_state *mi2s, uint8_t dev_id, bool master)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	uint32_t val;
	if (!IS_ERR(baddr)) {
		val = readl(baddr + MI2S_MODE_OFFSET);
		if (master) {
			writel(
			((val & ~HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_BMSK) |
			 (MI2S_MODE__MI2S_MASTER__MASTER <<
			  HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_SHFT)),
			baddr + MI2S_MODE_OFFSET);
		} else {
			writel(
			((val & ~HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_BMSK) |
			 (MI2S_MODE__MI2S_MASTER__SLAVE <<
			  HWIO_AUDIO1_MI2S_MODE_MI2S_MASTER_SHFT)),
			baddr + MI2S_MODE_OFFSET);
		}
	}
}
/* Set who control aux pcm path: adsp or MSM */
void aux_codec_pcm_path_ctl_en(bool msm_adsp_en)
{
	void __iomem *baddr = get_base_addr(&the_aux_pcm_state);
	uint32_t val;

	 if (!IS_ERR(baddr)) {
		val = readl(baddr + PCM_PATH_CTL_OFFSET);
		if (msm_adsp_en) { /* adsp */
			writel(
			((val & ~PCM_PATH_CTL__ADSP_CTL_EN_BMSK) |
			PCM_PATH_CTL__ADSP_CTL_EN__ADSP_V),
			baddr + PCM_PATH_CTL_OFFSET);
		} else { /* MSM */
			writel(
			((val & ~PCM_PATH_CTL__ADSP_CTL_EN_BMSK) |
			PCM_PATH_CTL__ADSP_CTL_EN__MSM_V),
			baddr + PCM_PATH_CTL_OFFSET);
		}
	}

	return;
}
Exemple #16
0
/* K8 systems have some devices (typically in the builtin northbridge)
   that are only accessible using type1
   Normally this can be expressed in the MCFG by not listing them
   and assigning suitable _SEGs, but this isn't implemented in some BIOS.
   Instead try to discover all devices on bus 0 that are unreachable using MM
   and fallback for them.
   We only do this for bus 0/seg 0 */
static __init void unreachable_devices(void)
{
	int i;
	unsigned long flags;

	for (i = 0; i < 32; i++) {
		u32 val1;
		u32 addr;

		pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1);
		if (val1 == 0xffffffff)
			continue;

		/* Locking probably not needed, but safer */
		spin_lock_irqsave(&pci_config_lock, flags);
		addr = get_base_addr(0, 0, PCI_DEVFN(i, 0));
		if (addr != 0)
			pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0));
		if (addr == 0 || readl((u32 __iomem *)mmcfg_virt_addr) != val1)
			set_bit(i, fallback_slots);
		spin_unlock_irqrestore(&pci_config_lock, flags);
	}
}
static void mi2s_set_word_type(struct mi2s_state *mi2s, uint8_t dev_id,
	uint8_t size)
{
	void __iomem *baddr = get_base_addr(mi2s, dev_id);
	uint32_t val;
	if (!IS_ERR(baddr)) {
		val = readl(baddr + MI2S_MODE_OFFSET);
		switch (size) {
		case WT_16_BIT:
			writel(
			((val &
			~HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_BMSK) |
			(MI2S_MODE__MI2S_TX_RX_WORD_TYPE__16_BIT <<
			HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_SHFT)),
			baddr + MI2S_MODE_OFFSET);
			break;
		case WT_24_BIT:
			writel(
			((val &
			~HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_BMSK) |
			(MI2S_MODE__MI2S_TX_RX_WORD_TYPE__24_BIT <<
			HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_SHFT)),
			baddr + MI2S_MODE_OFFSET);
			break;
		case WT_32_BIT:
			writel(
			((val &
			~HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_BMSK) |
			(MI2S_MODE__MI2S_TX_RX_WORD_TYPE__32_BIT <<
			HWIO_AUDIO1_MI2S_MODE_MI2S_TX_RX_WORD_TYPE_SHFT)),
			baddr + MI2S_MODE_OFFSET);
			break;
		default:
			break;
		}
	}
}
int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus,
				    unsigned int devfn)
{
	return get_base_addr(seg, bus, devfn) != 0;
}
bool mi2s_set_hdmi_input_path(uint8_t channels, uint8_t size,
		uint8_t sd_line_mask)
{
	bool ret_val = MI2S_TRUE;
	struct mi2s_state *mi2s = &the_mi2s_state;
	u8 sd_line, num_of_sd_lines = 0;
	void __iomem *baddr;
	uint32_t val;

	pr_debug("%s: channels = %u size = %u sd_line_mask = 0x%x\n", __func__,
		channels, size, sd_line_mask);

	if ((channels != 1) && (channels != MAX_NUM_CHANNELS_IN)) {

		pr_err("%s: invalid number of channels. channels = %u\n",
				__func__, channels);
		return  MI2S_FALSE;
	}

	if (size > WT_MAX) {

		pr_err("%s: mi2s word size can not be greater than 32 bits\n",
				__func__);
		return MI2S_FALSE;
	}

	sd_line_mask &=  MI2S_SD_LINE_MASK;

	if (!sd_line_mask) {
		pr_err("%s: Did not set any data lines to use "
			" sd_line_mask =0x%x\n", __func__, sd_line_mask);
		return  MI2S_FALSE;
	}

	num_of_sd_lines = num_of_bits_set(sd_line_mask);

	if (num_of_sd_lines != 1) {
		pr_err("%s: for two channel input only one SD lines is"
			" needed. num_of_sd_lines = %u sd_line_mask = 0x%x\n",
			__func__, num_of_sd_lines, sd_line_mask);
		return MI2S_FALSE;
	}

	/*Second argument to find_first_bit should be maximum number of
	bits interested*/
	sd_line = find_first_bit((unsigned long *)&sd_line_mask,
			sizeof(sd_line_mask) * 8);
	pr_debug("sd_line = %d\n", sd_line);

	/* Ensure sd_line parameter is valid (0-max) */
	if (sd_line > MAX_SD_LINES) {
		pr_err("%s: Line number can not be greater than = %u\n",
			__func__, MAX_SD_LINES);
		return MI2S_FALSE;
	}

	mutex_lock(&mi2s->mutex_lock);
	/* Put device in reset */
	mi2s_reset(mi2s, HDMI);

	mi2s_master(mi2s, HDMI, 1);

	/* Set word type */
	mi2s_set_word_type(mi2s, HDMI, size);

	/* Enable clock crossing synchronization of WR DMA ACK */
	mi2s_set_input_clk_synch(mi2s, HDMI);

	/* Ensure channels parameter is valid (non-zero, less than max,
	 * and even or mono)
	 */
	mi2s_set_input_num_channels(mi2s, HDMI, channels);

	mi2s_set_input_sd_line(mi2s, HDMI, sd_line);

	mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP << sd_line));

	baddr = get_base_addr(mi2s, HDMI);

	val = readl(baddr + MI2S_MODE_OFFSET);
	pr_debug("%s(): MI2S_MODE = 0x%x\n", __func__, val);

	val = readl(baddr + MI2S_RX_MODE_OFFSET);
	pr_debug("%s(): MI2S_RX_MODE = 0x%x\n", __func__, val);

	/* Release device from reset */
	mi2s_release(mi2s, HDMI);

	mutex_unlock(&mi2s->mutex_lock);
	mb();
	return ret_val;
}
bool mi2s_set_hdmi_output_path(uint8_t channels, uint8_t size,
		uint8_t sd_line_mask)
{
	bool ret_val = MI2S_TRUE;
	struct mi2s_state *mi2s = &the_mi2s_state;
	u8 sd_line, num_of_sd_lines = 0;
	void __iomem *baddr;
	uint32_t val;

	pr_debug("%s: channels = %u size = %u sd_line_mask = 0x%x\n", __func__,
		channels, size, sd_line_mask);

	if ((channels == 0) ||  (channels > MAX_NUM_CHANNELS_OUT) ||
		((channels != 1) && (channels % 2 != 0))) {

		pr_err("%s: invalid number of channels. channels = %u\n",
				__func__, channels);
		return  MI2S_FALSE;
	}

	sd_line_mask &=  MI2S_SD_LINE_MASK;

	if (!sd_line_mask) {
		pr_err("%s: Did not set any data lines to use "
			" sd_line_mask =0x%x\n", __func__, sd_line_mask);
		return  MI2S_FALSE;
	}

	mutex_lock(&mi2s->mutex_lock);
	/* Put device in reset */
	mi2s_reset(mi2s, HDMI);

	mi2s_master(mi2s, HDMI, 1);

	/* Set word type */
	if (size <= WT_MAX)
		mi2s_set_word_type(mi2s, HDMI, size);
	else
		ret_val = MI2S_FALSE;

	/* Enable clock crossing synchronization of RD DMA ACK */
	mi2s_set_output_clk_synch(mi2s, HDMI);

	mi2s_set_output_num_channels(mi2s, HDMI, channels);

	num_of_sd_lines = num_of_bits_set(sd_line_mask);
	/*Second argument to find_first_bit should be maximum number of
	bit*/

	sd_line = find_first_bit((unsigned long *)&sd_line_mask,
			sizeof(sd_line_mask) * 8);
	pr_debug("sd_line = %d\n", sd_line);

	if (channels == 1) {

		if (num_of_sd_lines != 1) {
			pr_err("%s: for one channel only one SD lines is"
				" needed. num_of_sd_lines = %u\n",
				__func__, num_of_sd_lines);

			ret_val = MI2S_FALSE;
			goto error;
		}

		if (sd_line != 0) {
			pr_err("%s: for one channel tx, need to use SD_0 "
					"sd_line = %u\n", __func__, sd_line);

			ret_val = MI2S_FALSE;
			goto error;
		}

		/* Enable SD line 0 for Tx (only option for
			 * mono audio)
		 */
		mi2s_set_sd(mi2s, HDMI, MI2S_SD_0_EN_MAP | MI2S_SD_0_TX_MAP);

	} else if (channels == 2) {

		if (num_of_sd_lines != 1) {
			pr_err("%s: for two channel only one SD lines is"
				" needed. num_of_sd_lines = %u\n",
				__func__, num_of_sd_lines);
			ret_val = MI2S_FALSE;
			goto error;
		}

		/* Enable single SD line for Tx */
		mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP << sd_line) |
				(MI2S_SD_0_TX_MAP << sd_line));

		/* Set 2-channel mapping */
		mi2s_set_output_2ch_map(mi2s, HDMI, sd_line);

	} else if (channels == 4) {

		if (num_of_sd_lines != 2) {
			pr_err("%s: for 4 channels two SD lines are"
				" needed. num_of_sd_lines = %u\\n",
				__func__, num_of_sd_lines);
			ret_val = MI2S_FALSE;
			goto error;
		}

		if ((sd_line_mask && MI2S_SD_0) &&
				(sd_line_mask && MI2S_SD_1)) {

			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
				MI2S_SD_1_EN_MAP) | (MI2S_SD_0_TX_MAP |
				MI2S_SD_1_TX_MAP));
			mi2s_set_output_4ch_map(mi2s, HDMI, MI2S_FALSE);

		} else if ((sd_line_mask && MI2S_SD_2) &&
				(sd_line_mask && MI2S_SD_3)) {

			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_2_EN_MAP |
				MI2S_SD_3_EN_MAP) | (MI2S_SD_2_TX_MAP |
				MI2S_SD_3_TX_MAP));

			mi2s_set_output_4ch_map(mi2s, HDMI, MI2S_TRUE);
		} else {

			pr_err("%s: for 4 channels invalid SD lines usage"
				" sd_line_mask = 0x%x\n",
				__func__, sd_line_mask);
			ret_val = MI2S_FALSE;
			goto error;
		}
	} else if (channels == 6) {

		if (num_of_sd_lines != 3) {
			pr_err("%s: for 6 channels three SD lines are"
				" needed. num_of_sd_lines = %u\n",
				__func__, num_of_sd_lines);
			ret_val = MI2S_FALSE;
			goto error;
		}

		if ((sd_line_mask && MI2S_SD_0) &&
			(sd_line_mask && MI2S_SD_1) &&
			(sd_line_mask && MI2S_SD_2)) {

			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
				MI2S_SD_1_EN_MAP | MI2S_SD_2_EN_MAP) |
				(MI2S_SD_0_TX_MAP | MI2S_SD_1_TX_MAP |
				MI2S_SD_2_TX_MAP));

		} else if ((sd_line_mask && MI2S_SD_1) &&
				(sd_line_mask && MI2S_SD_2) &&
				(sd_line_mask && MI2S_SD_3)) {

			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_1_EN_MAP |
				MI2S_SD_2_EN_MAP | MI2S_SD_3_EN_MAP) |
				(MI2S_SD_1_TX_MAP | MI2S_SD_2_TX_MAP |
				MI2S_SD_3_TX_MAP));

		} else {

			pr_err("%s: for 6 channels invalid SD lines usage"
				" sd_line_mask = 0x%x\n",
				__func__, sd_line_mask);
			ret_val = MI2S_FALSE;
			goto error;
		}
	} else if (channels == 8) {

		if (num_of_sd_lines != 4) {
			pr_err("%s: for 8 channels four SD lines are"
				" needed. num_of_sd_lines = %u\n",
				__func__, num_of_sd_lines);
			ret_val = MI2S_FALSE;
			goto error;
		}

		mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
			MI2S_SD_1_EN_MAP | MI2S_SD_2_EN_MAP |
			MI2S_SD_3_EN_MAP) | (MI2S_SD_0_TX_MAP |
			MI2S_SD_1_TX_MAP | MI2S_SD_2_TX_MAP |
			MI2S_SD_3_TX_MAP));
	} else {
		pr_err("%s: invalid number channels = %u\n",
				__func__, channels);
			ret_val = MI2S_FALSE;
			goto error;
	}

	baddr = get_base_addr(mi2s, HDMI);

	val = readl(baddr + MI2S_MODE_OFFSET);
	pr_debug("%s(): MI2S_MODE = 0x%x\n", __func__, val);

	val = readl(baddr + MI2S_TX_MODE_OFFSET);
	pr_debug("%s(): MI2S_TX_MODE = 0x%x\n", __func__, val);


error:
	/* Release device from reset */
	mi2s_release(mi2s, HDMI);

	mutex_unlock(&mi2s->mutex_lock);
	mb();
	return ret_val;
}