Esempio n. 1
0
static int amd_create_page_map(struct amd_page_map *page_map)
{
	int i;

	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
	if (page_map->real == NULL)
		return -ENOMEM;

#ifndef CONFIG_X86
	SetPageReserved(virt_to_page(page_map->real));
	global_cache_flush();
	page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
					    PAGE_SIZE);
	if (page_map->remapped == NULL) {
		ClearPageReserved(virt_to_page(page_map->real));
		free_page((unsigned long) page_map->real);
		page_map->real = NULL;
		return -ENOMEM;
	}
	global_cache_flush();
#else
	set_memory_uc((unsigned long)page_map->real, 1);
	page_map->remapped = page_map->real;
#endif

	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
		writel(agp_bridge->scratch_page, page_map->remapped+i);
		readl(page_map->remapped+i);	/* PCI Posting. */
	}

	return 0;
}
Esempio n. 2
0
/*
 * allocate a uncacheable page table.
 * return physical address.
 */
static phys_addr_t alloc_page_table(struct isp_mmu *mmu)
{
	int i;
	phys_addr_t page;
	void *virt;

	/*page table lock may needed here*/
	/*
	 * The slab allocator(kmem_cache and kmalloc family) doesn't handle
	 * GFP_DMA32 flag, so we have to use buddy allocator.
	 */
	if (totalram_pages > (unsigned long)NR_PAGES_2GB)
		virt = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32);
	else
		virt = kmem_cache_zalloc(mmu->tbl_cache, GFP_KERNEL);
	if (!virt)
		return (phys_addr_t)NULL_PAGE;

	/*
	 * we need a uncacheable page table.
	 */
#ifdef	CONFIG_X86
	set_memory_uc((unsigned long)virt, 1);
#endif

	page = virt_to_phys(virt);

	for (i = 0; i < 1024; i++) {
		/* NEED CHECK */
		atomisp_set_pte(page, i, mmu->driver->null_pte);
	}

	return page;
}
/*
 * allocate a uncacheable page table.
 * return physical address.
 */
static phys_addr_t alloc_page_table(struct isp_mmu *mmu)
{
	int i;
	phys_addr_t page;
	/*page table lock may needed here*/
#ifdef USE_KMEM_CACHE
	void *virt = kmem_cache_zalloc(mmu->tbl_cache, GFP_KERNEL);
#else
	void *virt = (void *)__get_free_page(GFP_KERNEL);
#endif
	if (!virt)
		return (phys_addr_t)NULL_PAGE;

	/*
	 * we need a uncacheable page table.
	 */
#ifdef	CONFIG_X86
	set_memory_uc((unsigned long)virt, 1);
#endif

	page = virt_to_phys(virt);

	for (i = 0; i < 1024; i++) {
		/* NEED CHECK */
		atomisp_set_pte(page, i, mmu->driver->null_pte);
	}

	return page;
}
Esempio n. 4
0
static inline int teradimm_cache_COMMAND(struct td_mapper *m,
		int alias, int id)
{
	off_t off;

	VALIDATE_TYPE_ALIAS_ID(m, COMMAND, alias, id);

	off = TERADIMM_OFFSET(COMMAND,alias,id, m->phys_avoid_mask);

	VALIDATE_OFFSET(m, COMMAND, alias, id, off);

	REMEMBER_CACHED_MAP_PTR(m, COMMAND, alias, id, off, PAGE_SIZE);

#ifdef CONFIG_TERADIMM_FORCE_CMD_UC_MAP
	if (td_mapper_cmd_force_uc(m, id)) {
		void *ptr = CACHED_MAP_PTR(m,COMMAND,alias,id);
		unsigned long addr = ((unsigned long)ptr) & PAGE_MASK;
		int rc = set_memory_uc(addr, 1);
		if ( WARN_ON_ONCE(rc) ) {
			pr_err("UC REMAP FAILED %p -> %016lx, rc=%d\n",
				ptr, addr, rc);

		}
	}
#endif

	return 0;
}
static int amd_create_page_map(struct amd_page_map *page_map)
{
	int i;

	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
	if (page_map->real == NULL)
		return -ENOMEM;

	set_memory_uc((unsigned long)page_map->real, 1);
	page_map->remapped = page_map->real;

	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
		writel(agp_bridge->scratch_page, page_map->remapped+i);
		readl(page_map->remapped+i);	
	}

	return 0;
}
Esempio n. 6
0
static int serverworks_create_page_map(struct serverworks_page_map *page_map)
{
	int i;

	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
	if (page_map->real == NULL) {
		return -ENOMEM;
	}

	set_memory_uc((unsigned long)page_map->real, 1);
	page_map->remapped = page_map->real;

	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++)
		writel(agp_bridge->scratch_page, page_map->remapped+i);
		/* Red Pen: Everyone else does pci posting flush here */

	return 0;
}
Esempio n. 7
0
static int ati_create_page_map(struct ati_page_map *page_map)
{
	int i, err = 0;

	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
	if (page_map->real == NULL)
		return -ENOMEM;

	set_memory_uc((unsigned long)page_map->real, 1);
	err = map_page_into_agp(virt_to_page(page_map->real));
	page_map->remapped = page_map->real;

	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
		writel(agp_bridge->scratch_page, page_map->remapped+i);
		readl(page_map->remapped+i);	/* PCI Posting. */
	}

	return 0;
}
Esempio n. 8
0
/**
 * snd_intelhad_init_audio_ctrl - to initialize audio channel status
 * registers and confgiuration registers
 *
 * @substream:substream for which the prepare function is called
 * @intelhaddata:substream private data
 *
 * This function is called in the prepare callback
 */
int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream,
					struct snd_intelhad *intelhaddata,
					int flag_silence)
{
	union aud_cfg cfg_val = {.cfg_regval = 0};
	union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0};
	union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0};
	union aud_buf_config buf_cfg = {.buf_cfgval = 0};
	u8 channels;
	int format, retval;
	u32 data;

	ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits &
						IEC958_AES0_NONAUDIO)>>1;
	ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits &
						IEC958_AES3_CON_CLOCK)>>4;
	switch (substream->runtime->rate) {
	case AUD_SAMPLE_RATE_32:
		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ;
	break;

	case AUD_SAMPLE_RATE_44_1:
	case AUD_SAMPLE_RATE_88_2:
	case AUD_SAMPLE_RATE_176_4:
		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_44KHZ;
	break;

	case AUD_SAMPLE_RATE_48:
	case AUD_SAMPLE_RATE_96:
	case HAD_MAX_RATE:
		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_48KHZ;
	break;

	default:
		return -EINVAL;
	break;

	}
	had_write_register(AUD_CH_STATUS_0, ch_stat0.status_0_regval);

	format = substream->runtime->format;

	if (format == SNDRV_PCM_FORMAT_S16_LE) {
		ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_20;
		ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_16BITS;
	} else if (format == SNDRV_PCM_FORMAT_S24_LE) {
		ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_24;
		ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_24BITS;
	} else {
		ch_stat1.status_1_regx.max_wrd_len = 0;
		ch_stat1.status_1_regx.wrd_len = 0;
	}
	had_write_register(AUD_CH_STATUS_1, ch_stat1.status_1_regval);

	buf_cfg.buf_cfg_regx.fifo_width = FIFO_THRESHOLD;
	buf_cfg.buf_cfg_regx.aud_delay = 0;
	had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval);

	channels = substream->runtime->channels;

	switch (channels) {
	case 1:
	case 2:
		cfg_val.cfg_regx.num_ch = CH_STEREO;
		cfg_val.cfg_regx.layout = LAYOUT0;
	break;

	case 3:
	case 4:
		cfg_val.cfg_regx.num_ch = CH_THREE_FOUR;
		cfg_val.cfg_regx.layout = LAYOUT1;
	break;

	case 5:
	case 6:
		cfg_val.cfg_regx.num_ch = CH_FIVE_SIX;
		cfg_val.cfg_regx.layout = LAYOUT1;
	break;

	case 7:
	case 8:
		cfg_val.cfg_regx.num_ch = CH_SEVEN_EIGHT;
		cfg_val.cfg_regx.layout = LAYOUT1;
	break;

	}

	cfg_val.cfg_regx.val_bit = 1;
	had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
	return 0;
}

/**
 * snd_intelhad_prog_dip - to initialize Data Island Packets registers
 *
 * @substream:substream for which the prepare function is called
 * @intelhaddata:substream private data
 *
 * This function is called in the prepare callback
 */
static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream,
				struct snd_intelhad *intelhaddata,
				int flag_silence)
{
	int i;
	union aud_ctrl_st ctrl_state = {.ctrl_val = 0};
	union aud_info_frame2 frame2 = {.fr2_val = 0};
	union aud_info_frame3 frame3 = {.fr3_val = 0};
	u8 checksum = 0;

	had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);

	frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;

	/*TODO: Read from intelhaddata->eeld.speaker_allocation_block;*/
	frame3.fr3_regx.chnl_alloc = CHANNEL_ALLOCATION;

	/*Calculte the byte wide checksum for all valid DIP words*/
	for (i = 0; i < BYTES_PER_WORD; i++)
		checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
	for (i = 0; i < BYTES_PER_WORD; i++)
		checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
	for (i = 0; i < BYTES_PER_WORD; i++)
		checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;

	frame2.fr2_regx.chksum = -(checksum);

	had_write_register(AUD_HDMIW_INFOFR, INFO_FRAME_WORD1);
	had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val);
	had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val);

	/* program remaining DIP words with zero */
	for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
		had_write_register(AUD_HDMIW_INFOFR, 0x0);

	ctrl_state.ctrl_regx.dip_freq = 1;
	ctrl_state.ctrl_regx.dip_en_sta = 1;
	had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
}

/**
 * snd_intelhad_prog_buffer - programs buffer
 * address and length registers
 *
 * @substream:substream for which the prepare function is called
 * @intelhaddata:substream private data
 *
 * This function programs ring buffer address and length into registers.
 */
int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata,
					int start, int end)
{
	u32 ring_buf_addr, ring_buf_size, period_bytes;
	u8 i, num_periods;
	struct snd_pcm_substream *substream;

	substream = intelhaddata->stream_info.had_substream;
	if (!substream) {
		pr_err("substream is NULL\n");
		dump_stack();
		return 0;
	}

	ring_buf_addr = substream->runtime->dma_addr;
	ring_buf_size = snd_pcm_lib_buffer_bytes(substream);
	intelhaddata->stream_info.ring_buf_size = ring_buf_size;
	period_bytes = frames_to_bytes(substream->runtime,
				substream->runtime->period_size);
	num_periods = substream->runtime->periods;

	/* buffer addr should  be 64 byte aligned, period bytes
	 will be used to calculate addr offset*/
	period_bytes &= ~0x3F;

	/* Hardware supports MAX_PERIODS buffers */
	if (end >= HAD_MAX_PERIODS)
		return -EINVAL;

	for (i = start; i <= end; i++) {
		/* Program the buf registers with addr and len */
		intelhaddata->buf_info[i].buf_addr = ring_buf_addr +
							 (i * period_bytes);
		if (i < num_periods-1)
			intelhaddata->buf_info[i].buf_size = period_bytes;
		else
			intelhaddata->buf_info[i].buf_size = ring_buf_size -
							(period_bytes*i);

		had_write_register(AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH),
					intelhaddata->buf_info[i].buf_addr |
					BIT(0) | BIT(1));
		had_write_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
					period_bytes);
		intelhaddata->buf_info[i].is_valid = true;
	}
	pr_debug("%s:buf[%d-%d] addr=%#x  and size=%d\n", __func__, start, end,
			intelhaddata->buf_info[start].buf_addr,
			intelhaddata->buf_info[start].buf_size);
	intelhaddata->valid_buf_cnt = num_periods;
	return 0;
}

inline int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
{
	int i, retval = 0;
	u32 len[4];

	for (i = 0; i < 4 ; i++) {
		had_read_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
					&len[i]);
		if (!len[i])
			retval++;
	}
	if (retval != 1) {
		for (i = 0; i < 4 ; i++)
			pr_debug("buf[%d] size=%d\n", i, len[i]);
	}

	return retval;
}

/**
 * snd_intelhad_prog_cts - Program HDMI audio CTS value
 *
 * @aud_samp_freq: sampling frequency of audio data
 * @tmds: sampling frequency of the display data
 * @n_param: N value, depends on aud_samp_freq
 * @intelhaddata:substream private data
 *
 * Program CTS register based on the audio and display sampling frequency
 */
static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, u32 n_param,
				struct snd_intelhad *intelhaddata)
{
	u32 cts_val;
	u64 dividend, divisor;

	/* Calculate CTS according to HDMI 1.3a spec*/
	dividend = (u64)tmds * n_param*1000;
	divisor = 128 * aud_samp_freq;
	cts_val = div64_u64(dividend, divisor);
	pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n",
			tmds, n_param, cts_val);
	had_write_register(AUD_HDMI_CTS, (BIT(20) | cts_val));
}

/**
 * snd_intelhad_prog_n - Program HDMI audio N value
 *
 * @aud_samp_freq: sampling frequency of audio data
 * @n_param: N value, depends on aud_samp_freq
 * @intelhaddata:substream private data
 *
 * This function is called in the prepare callback.
 * It programs based on the audio and display sampling frequency
 */
static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param,
				struct snd_intelhad *intelhaddata)
{
	u32 n_val;
	int retval = 0;

	/* Select N according to HDMI 1.3a spec*/
	switch (aud_samp_freq) {
	case AUD_SAMPLE_RATE_32:
		n_val = 4096;
	break;

	case AUD_SAMPLE_RATE_44_1:
		n_val = 6272;
	break;

	case AUD_SAMPLE_RATE_48:
		n_val = 6144;
	break;

	case AUD_SAMPLE_RATE_88_2:
		n_val = 12544;
	break;

	case AUD_SAMPLE_RATE_96:
		n_val = 12288;
	break;

	case AUD_SAMPLE_RATE_176_4:
		n_val = 25088;
	break;

	case HAD_MAX_RATE:
		n_val = 24576;
	break;

	default:
		retval = -EINVAL;
	break;

	}
	if (retval)
		return retval;
	had_write_register(AUD_N_ENABLE, (BIT(20) | n_val));
	*n_param = n_val;
	return retval;
}

/**
* snd_intelhad_open - stream initializations are done here
* @substream:substream for which the stream function is called
*
* This function is called whenever a PCM stream is opened
*/
static int snd_intelhad_open(struct snd_pcm_substream *substream)
{
	struct snd_intelhad *intelhaddata;
	struct snd_pcm_runtime *runtime;
	struct had_stream_pvt *stream;
	struct had_pvt_data *had_stream;
	int retval;

	pr_debug("snd_intelhad_open called\n");
	intelhaddata = snd_pcm_substream_chip(substream);
	had_stream = intelhaddata->private_data;

	/*
	 * HDMI driver might suspend the device already,
	 * so we return it on
	 */
	if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
			OSPM_UHB_FORCE_POWER_ON)) {
		pr_err("HDMI device can't be turned on\n");
		return -ENODEV;
	}

	if (had_get_hwstate(intelhaddata)) {
		pr_err("%s: HDMI cable plugged-out\n", __func__);
		ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
		return -ENODEV;
	}
	runtime = substream->runtime;

	/* Check, if device already in use */
	if (runtime->private_data) {
		pr_err("Device already in use\n");
		ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
		return -EBUSY;
	}

	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);

	/* set the runtime hw parameter with local snd_pcm_hardware struct */
	runtime->hw = snd_intel_hadstream;

	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
	if (!stream) {
		retval = -ENOMEM;
		goto exit_err;
	}
	stream->stream_status = STREAM_INIT;
	runtime->private_data = stream;

	retval = snd_pcm_hw_constraint_integer(runtime,
			 SNDRV_PCM_HW_PARAM_PERIODS);
	if (retval < 0) {
		kfree(stream);
		goto exit_err;
	}

	/* Make sure, that the period size is always aligned
	 * 64byte boundary
	 */
	retval = snd_pcm_hw_constraint_step(substream->runtime, 0,
			SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
	if (retval < 0) {
		pr_err("%s:step_size=64 failed,err=%d\n", __func__, retval);
		kfree(stream);
		goto exit_err;
	}

	return retval;
exit_err:
	runtime->private_data = NULL;
	return retval;
}

/**
* had_period_elapsed - updates the hardware pointer status
* @had_substream:substream for which the stream function is called
*
*/
static void had_period_elapsed(void *had_substream)
{
	struct snd_pcm_substream *substream = had_substream;
	struct had_stream_pvt *stream;

	if (!substream || !substream->runtime)
		return;
	stream = substream->runtime->private_data;
	if (!stream)
		return;

	if (stream->stream_status != STREAM_RUNNING)
		return;
	snd_pcm_period_elapsed(substream);
	return;
}

/**
* snd_intelhad_init_stream - internal function to initialize stream info
* @substream:substream for which the stream function is called
*
*/
static int snd_intelhad_init_stream(struct snd_pcm_substream *substream)
{
	struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream);

	pr_debug("setting buffer ptr param\n");
	intelhaddata->stream_info.period_elapsed = had_period_elapsed;
	intelhaddata->stream_info.had_substream = substream;
	intelhaddata->stream_info.buffer_ptr = 0;
	intelhaddata->stream_info.buffer_rendered = 0;
	intelhaddata->stream_info.sfreq = substream->runtime->rate;
	return 0;
}

/**
 * snd_intelhad_close- to free parameteres when stream is stopped
 *
 * @substream:  substream for which the function is called
 *
 * This function is called by ALSA framework when stream is stopped
 */
static int snd_intelhad_close(struct snd_pcm_substream *substream)
{
	struct snd_intelhad *intelhaddata;
	struct snd_pcm_runtime *runtime;

	pr_debug("snd_intelhad_close called\n");
	intelhaddata = snd_pcm_substream_chip(substream);
	runtime = substream->runtime;

	intelhaddata->stream_info.buffer_rendered = 0;
	intelhaddata->stream_info.buffer_ptr = 0;
	intelhaddata->stream_info.str_id = 0;
	intelhaddata->stream_info.had_substream = NULL;

	/* Check if following drv_status modification is required - VA */
	if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED)
		intelhaddata->drv_status = HAD_DRV_CONNECTED;
	kfree(runtime->private_data);
	runtime->private_data = NULL;
	return 0;
}

/**
 * snd_intelhad_hw_params- to setup the hardware parameters
 * like allocating the buffers
 *
 * @substream:  substream for which the function is called
 * @hw_params: hardware parameters
 *
 * This function is called by ALSA framework when hardware params are set
 */
static int snd_intelhad_hw_params(struct snd_pcm_substream *substream,
				    struct snd_pcm_hw_params *hw_params)
{
	unsigned long addr;
	int pages, buf_size, retval;

	BUG_ON(!hw_params);

	buf_size = params_buffer_bytes(hw_params);
	retval = snd_pcm_lib_malloc_pages(substream, buf_size);
	if (retval < 0)
		return retval;
	pr_debug("%s:allocated memory = %d\n", __func__, buf_size);
	/* mark the pages as uncached region */
	addr = (unsigned long) substream->runtime->dma_area;
	pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
	retval = set_memory_uc(addr, pages);
	if (retval) {
		pr_err("set_memory_uc failed.Error:%d\n", retval);
		return retval;
	}
	memset(substream->runtime->dma_area, 0, buf_size);

	return retval;
}

/**
 * snd_intelhad_hw_free- to release the resources allocated during
 * hardware params setup
 *
 * @substream:  substream for which the function is called
 *
 * This function is called by ALSA framework before close callback.
 *
 */
static int snd_intelhad_hw_free(struct snd_pcm_substream *substream)
{
	unsigned long addr;
	u32 pages;

	pr_debug("snd_intelhad_hw_free called\n");

	/* mark back the pages as cached/writeback region before the free */
	addr = (unsigned long) substream->runtime->dma_area;
	pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
	set_memory_wb(addr, pages);
	return snd_pcm_lib_free_pages(substream);
}