| /* Copyright (c) 2012, Code Aurora Forum. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| |
| #include <asm/mach-types.h> |
| #include <linux/platform_device.h> |
| #include <linux/android_pmem.h> |
| #include <linux/gfp.h> |
| #include <mach/msm_memtypes.h> |
| #include <mach/board.h> |
| #include <mach/msm_rpcrouter.h> |
| #include <mach/socinfo.h> |
| |
| #include "devices.h" |
| #include "board-msm7627a.h" |
| #include "devices-msm7x2xa.h" |
| |
| static struct android_pmem_platform_data android_pmem_adsp_pdata = { |
| .name = "pmem_adsp", |
| .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, |
| .cached = 1, |
| .memory_type = MEMTYPE_EBI1, |
| .request_region = request_fmem_c_region, |
| .release_region = release_fmem_c_region, |
| .reusable = 1, |
| }; |
| |
| static struct platform_device android_pmem_adsp_device = { |
| .name = "android_pmem", |
| .id = 1, |
| .dev = { .platform_data = &android_pmem_adsp_pdata }, |
| }; |
| |
| #define SND(desc, num) { .name = #desc, .id = num } |
| static struct snd_endpoint snd_endpoints_list[] = { |
| SND(HANDSET, 0), |
| SND(MONO_HEADSET, 2), |
| SND(HEADSET, 3), |
| SND(SPEAKER, 6), |
| SND(TTY_HEADSET, 8), |
| SND(TTY_VCO, 9), |
| SND(TTY_HCO, 10), |
| SND(BT, 12), |
| SND(IN_S_SADC_OUT_HANDSET, 16), |
| SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25), |
| SND(FM_DIGITAL_STEREO_HEADSET, 26), |
| SND(FM_DIGITAL_SPEAKER_PHONE, 27), |
| SND(FM_DIGITAL_BT_A2DP_HEADSET, 28), |
| SND(STEREO_HEADSET_AND_SPEAKER, 31), |
| SND(CURRENT, 0x7FFFFFFE), |
| SND(FM_ANALOG_STEREO_HEADSET, 35), |
| SND(FM_ANALOG_STEREO_HEADSET_CODEC, 36), |
| }; |
| #undef SND |
| |
| static struct msm_snd_endpoints msm_device_snd_endpoints = { |
| .endpoints = snd_endpoints_list, |
| .num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint) |
| }; |
| |
| static struct platform_device msm_device_snd = { |
| .name = "msm_snd", |
| .id = -1, |
| .dev = { |
| .platform_data = &msm_device_snd_endpoints |
| }, |
| }; |
| |
| #define DEC0_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \ |
| (1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \ |
| (1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \ |
| (1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \ |
| (1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \ |
| (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP)) |
| #define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \ |
| (1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \ |
| (1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \ |
| (1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \ |
| (1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \ |
| (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP)) |
| #define DEC2_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \ |
| (1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \ |
| (1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \ |
| (1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \ |
| (1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \ |
| (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP)) |
| #define DEC3_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \ |
| (1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \ |
| (1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \ |
| (1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \ |
| (1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \ |
| (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP)) |
| #define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI) |
| |
| static unsigned int dec_concurrency_table[] = { |
| /* Audio LP */ |
| (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DMA)), 0, |
| 0, 0, 0, |
| |
| /* Concurrency 1 */ |
| (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC4_FORMAT), |
| |
| /* Concurrency 2 */ |
| (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC4_FORMAT), |
| |
| /* Concurrency 3 */ |
| (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC4_FORMAT), |
| |
| /* Concurrency 4 */ |
| (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC4_FORMAT), |
| |
| /* Concurrency 5 */ |
| (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC4_FORMAT), |
| |
| /* Concurrency 6 */ |
| (DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| 0, 0, 0, |
| |
| /* Concurrency 7 */ |
| (DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)), |
| (DEC4_FORMAT), |
| }; |
| |
| #define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \ |
| .module_queueid = queueid, .module_decid = decid, \ |
| .nr_codec_support = nr_codec} |
| |
| static struct msm_adspdec_info dec_info_list[] = { |
| DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */ |
| DEC_INFO("AUDPLAY1TASK", 14, 1, 11), /* AudPlay1BitStreamCtrlQueue */ |
| DEC_INFO("AUDPLAY2TASK", 15, 2, 11), /* AudPlay2BitStreamCtrlQueue */ |
| DEC_INFO("AUDPLAY3TASK", 16, 3, 11), /* AudPlay3BitStreamCtrlQueue */ |
| DEC_INFO("AUDPLAY4TASK", 17, 4, 1), /* AudPlay4BitStreamCtrlQueue */ |
| }; |
| |
| static struct msm_adspdec_database msm_device_adspdec_database = { |
| .num_dec = ARRAY_SIZE(dec_info_list), |
| .num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \ |
| ARRAY_SIZE(dec_info_list)), |
| .dec_concurrency_table = dec_concurrency_table, |
| .dec_info_list = dec_info_list, |
| }; |
| |
| static struct platform_device msm_device_adspdec = { |
| .name = "msm_adspdec", |
| .id = -1, |
| .dev = { |
| .platform_data = &msm_device_adspdec_database |
| }, |
| }; |
| |
| static struct android_pmem_platform_data android_pmem_audio_pdata = { |
| .name = "pmem_audio", |
| .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, |
| .cached = 0, |
| .memory_type = MEMTYPE_EBI1, |
| }; |
| |
| static struct platform_device android_pmem_audio_device = { |
| .name = "android_pmem", |
| .id = 2, |
| .dev = { .platform_data = &android_pmem_audio_pdata }, |
| }; |
| |
| static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE; |
| static int __init pmem_kernel_ebi1_size_setup(char *p) |
| { |
| pmem_kernel_ebi1_size = memparse(p, NULL); |
| return 0; |
| } |
| early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup); |
| |
| static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE; |
| static int __init pmem_audio_size_setup(char *p) |
| { |
| pmem_audio_size = memparse(p, NULL); |
| return 0; |
| } |
| early_param("pmem_audio_size", pmem_audio_size_setup); |
| |
| static struct memtype_reserve msm7627a_reserve_table[] __initdata = { |
| [MEMTYPE_SMI] = { |
| }, |
| [MEMTYPE_EBI0] = { |
| .flags = MEMTYPE_FLAGS_1M_ALIGN, |
| }, |
| [MEMTYPE_EBI1] = { |
| .flags = MEMTYPE_FLAGS_1M_ALIGN, |
| }, |
| }; |
| |
| static struct android_pmem_platform_data android_pmem_pdata = { |
| .name = "pmem", |
| .allocator_type = PMEM_ALLOCATORTYPE_BITMAP, |
| .cached = 1, |
| .memory_type = MEMTYPE_EBI1, |
| }; |
| static struct platform_device android_pmem_device = { |
| .name = "android_pmem", |
| .id = 0, |
| .dev = { .platform_data = &android_pmem_pdata }, |
| }; |
| |
| static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = { |
| &android_pmem_adsp_pdata, |
| &android_pmem_audio_pdata, |
| &android_pmem_pdata, |
| }; |
| |
| static unsigned pmem_mdp_size; |
| static unsigned pmem_adsp_size; |
| |
| static int __init pmem_mdp_size_setup(char *p) |
| { |
| pmem_mdp_size = memparse(p, NULL); |
| return 0; |
| } |
| early_param("pmem_mdp_size", pmem_mdp_size_setup); |
| |
| static int __init pmem_adsp_size_setup(char *p) |
| { |
| pmem_adsp_size = memparse(p, NULL); |
| return 0; |
| } |
| early_param("pmem_adsp_size", pmem_adsp_size_setup); |
| |
| static void __init msm7627a_size_pmem_devices(void) |
| { |
| unsigned int i; |
| unsigned int reusable_count = 0; |
| |
| if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) { |
| pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE; |
| pmem_adsp_size = MSM7x25A_MSM_PMEM_ADSP_SIZE; |
| } else { |
| pmem_mdp_size = MSM_PMEM_MDP_SIZE; |
| pmem_adsp_size = MSM_PMEM_ADSP_SIZE; |
| } |
| |
| android_pmem_adsp_pdata.size = pmem_adsp_size; |
| android_pmem_pdata.size = pmem_mdp_size; |
| android_pmem_audio_pdata.size = pmem_audio_size; |
| |
| fmem_pdata.size = 0; |
| |
| /* Find pmem devices that should use FMEM (reusable) memory. |
| */ |
| for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) { |
| struct android_pmem_platform_data *pdata = pmem_pdata_array[i]; |
| |
| if (!reusable_count && pdata->reusable) |
| fmem_pdata.size += pdata->size; |
| |
| reusable_count += (pdata->reusable) ? 1 : 0; |
| |
| if (pdata->reusable && reusable_count > 1) { |
| pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n", |
| __func__, pdata->name); |
| pdata->reusable = 0; |
| } |
| } |
| } |
| |
| static void __init qrd7627a_size_pmem_devices(void) |
| { |
| unsigned int i; |
| unsigned int reusable_count = 0; |
| |
| pmem_mdp_size = QRD_PMEM_MDP_SIZE; |
| pmem_adsp_size = QRD_PMEM_ADSP_SIZE; |
| |
| android_pmem_adsp_pdata.size = pmem_adsp_size; |
| android_pmem_pdata.size = pmem_mdp_size; |
| android_pmem_audio_pdata.size = pmem_audio_size; |
| |
| fmem_pdata.size = 0; |
| |
| /* Find pmem devices that should use FMEM (reusable) memory. |
| */ |
| for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) { |
| struct android_pmem_platform_data *pdata = pmem_pdata_array[i]; |
| |
| if (!reusable_count && pdata->reusable) |
| fmem_pdata.size += pdata->size; |
| |
| reusable_count += (pdata->reusable) ? 1 : 0; |
| |
| if (pdata->reusable && reusable_count > 1) { |
| pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n", |
| __func__, pdata->name); |
| pdata->reusable = 0; |
| } |
| } |
| } |
| |
| static void __init reserve_memory_for(struct android_pmem_platform_data *p) |
| { |
| msm7627a_reserve_table[p->memory_type].size += p->size; |
| } |
| |
| static void __init msm7627a_reserve_pmem_memory(void) |
| { |
| unsigned int i; |
| for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) { |
| if (!pmem_pdata_array[i]->reusable) |
| reserve_memory_for(pmem_pdata_array[i]); |
| } |
| |
| msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; |
| } |
| |
| static void __init qrd7627a_reserve_pmem_memory(void) |
| { |
| reserve_memory_for(&android_pmem_adsp_pdata); |
| reserve_memory_for(&android_pmem_pdata); |
| reserve_memory_for(&android_pmem_audio_pdata); |
| msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size; |
| } |
| |
| static void __init msm7627a_calculate_reserve_sizes(void) |
| { |
| msm7627a_size_pmem_devices(); |
| msm7627a_reserve_pmem_memory(); |
| } |
| |
| static void __init qrd7627a_calculate_reserve_sizes(void) |
| { |
| qrd7627a_size_pmem_devices(); |
| qrd7627a_reserve_pmem_memory(); |
| } |
| |
| static int msm7627a_paddr_to_memtype(unsigned int paddr) |
| { |
| return MEMTYPE_EBI1; |
| } |
| |
| static struct reserve_info msm7627a_reserve_info __initdata = { |
| .memtype_reserve_table = msm7627a_reserve_table, |
| .calculate_reserve_sizes = msm7627a_calculate_reserve_sizes, |
| .paddr_to_memtype = msm7627a_paddr_to_memtype, |
| }; |
| |
| static struct reserve_info qrd7627a_reserve_info __initdata = { |
| .memtype_reserve_table = msm7627a_reserve_table, |
| .calculate_reserve_sizes = qrd7627a_calculate_reserve_sizes, |
| .paddr_to_memtype = msm7627a_paddr_to_memtype, |
| }; |
| |
| void __init msm7627a_reserve(void) |
| { |
| reserve_info = &msm7627a_reserve_info; |
| msm_reserve(); |
| fmem_pdata.phys = reserve_memory_for_fmem(fmem_pdata.size); |
| } |
| |
| void __init qrd7627a_reserve(void) |
| { |
| reserve_info = &qrd7627a_reserve_info; |
| msm_reserve(); |
| fmem_pdata.phys = reserve_memory_for_fmem(fmem_pdata.size); |
| } |
| |
| static struct platform_device *audio_devices[] __initdata = { |
| &android_pmem_device, |
| &android_pmem_adsp_device, |
| &android_pmem_audio_device, |
| &msm_device_adspdec, |
| &msm_device_snd, |
| }; |
| |
| void __init msm_adsp_add_pdev(void) |
| { |
| int rc = 0; |
| struct rpc_board_dev *rpc_adsp_pdev; |
| |
| rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL); |
| if (rpc_adsp_pdev == NULL) { |
| pr_err("%s: Memory Allocation failure\n", __func__); |
| return; |
| } |
| rpc_adsp_pdev->prog = ADSP_RPC_PROG; |
| |
| if (cpu_is_msm8625()) |
| rpc_adsp_pdev->pdev = msm8625_device_adsp; |
| else |
| rpc_adsp_pdev->pdev = msm_adsp_device; |
| rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1); |
| if (rc < 0) { |
| pr_err("%s: return val: %d\n", __func__, rc); |
| kfree(rpc_adsp_pdev); |
| } |
| |
| platform_add_devices(audio_devices, |
| ARRAY_SIZE(audio_devices)); |
| |
| } |