10aeed3e9SJustin Hibbits /*- 20aeed3e9SJustin Hibbits * Copyright (c) 2011-2012 Semihalf. 30aeed3e9SJustin Hibbits * All rights reserved. 40aeed3e9SJustin Hibbits * 50aeed3e9SJustin Hibbits * Redistribution and use in source and binary forms, with or without 60aeed3e9SJustin Hibbits * modification, are permitted provided that the following conditions 70aeed3e9SJustin Hibbits * are met: 80aeed3e9SJustin Hibbits * 1. Redistributions of source code must retain the above copyright 90aeed3e9SJustin Hibbits * notice, this list of conditions and the following disclaimer. 100aeed3e9SJustin Hibbits * 2. Redistributions in binary form must reproduce the above copyright 110aeed3e9SJustin Hibbits * notice, this list of conditions and the following disclaimer in the 120aeed3e9SJustin Hibbits * documentation and/or other materials provided with the distribution. 130aeed3e9SJustin Hibbits * 140aeed3e9SJustin Hibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 150aeed3e9SJustin Hibbits * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 160aeed3e9SJustin Hibbits * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 170aeed3e9SJustin Hibbits * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 180aeed3e9SJustin Hibbits * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 190aeed3e9SJustin Hibbits * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 200aeed3e9SJustin Hibbits * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 210aeed3e9SJustin Hibbits * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 220aeed3e9SJustin Hibbits * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 230aeed3e9SJustin Hibbits * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 240aeed3e9SJustin Hibbits * SUCH DAMAGE. 250aeed3e9SJustin Hibbits */ 260aeed3e9SJustin Hibbits 270aeed3e9SJustin Hibbits #include <sys/cdefs.h> 280aeed3e9SJustin Hibbits __FBSDID("$FreeBSD$"); 290aeed3e9SJustin Hibbits 300aeed3e9SJustin Hibbits #include <sys/param.h> 310aeed3e9SJustin Hibbits #include <sys/systm.h> 320aeed3e9SJustin Hibbits #include <sys/kernel.h> 330aeed3e9SJustin Hibbits #include <sys/module.h> 340aeed3e9SJustin Hibbits #include <sys/bus.h> 350aeed3e9SJustin Hibbits #include <sys/rman.h> 360aeed3e9SJustin Hibbits #include <sys/malloc.h> 370aeed3e9SJustin Hibbits 380aeed3e9SJustin Hibbits #include <dev/fdt/fdt_common.h> 390aeed3e9SJustin Hibbits #include <dev/ofw/ofw_bus.h> 400aeed3e9SJustin Hibbits #include <dev/ofw/ofw_bus_subr.h> 410aeed3e9SJustin Hibbits 420aeed3e9SJustin Hibbits #include "opt_platform.h" 430aeed3e9SJustin Hibbits 440aeed3e9SJustin Hibbits #include <contrib/ncsw/inc/Peripherals/fm_ext.h> 450aeed3e9SJustin Hibbits #include <contrib/ncsw/inc/Peripherals/fm_muram_ext.h> 460aeed3e9SJustin Hibbits #include <contrib/ncsw/inc/ncsw_ext.h> 470aeed3e9SJustin Hibbits #include <contrib/ncsw/integrations/fman_ucode.h> 480aeed3e9SJustin Hibbits 490aeed3e9SJustin Hibbits #include "fman.h" 500aeed3e9SJustin Hibbits 510aeed3e9SJustin Hibbits 520aeed3e9SJustin Hibbits /** 530aeed3e9SJustin Hibbits * @group FMan private defines. 540aeed3e9SJustin Hibbits * @{ 550aeed3e9SJustin Hibbits */ 560aeed3e9SJustin Hibbits enum fman_irq_enum { 570aeed3e9SJustin Hibbits FMAN_IRQ_NUM = 0, 580aeed3e9SJustin Hibbits FMAN_ERR_IRQ_NUM = 1 590aeed3e9SJustin Hibbits }; 600aeed3e9SJustin Hibbits 610aeed3e9SJustin Hibbits enum fman_mu_ram_map { 620aeed3e9SJustin Hibbits FMAN_MURAM_OFF = 0x0, 630aeed3e9SJustin Hibbits FMAN_MURAM_SIZE = 0x28000 640aeed3e9SJustin Hibbits }; 650aeed3e9SJustin Hibbits 660aeed3e9SJustin Hibbits struct fman_config { 670aeed3e9SJustin Hibbits device_t fman_device; 680aeed3e9SJustin Hibbits uintptr_t mem_base_addr; 69*f77405e3SJustin Hibbits uintptr_t irq_num; 70*f77405e3SJustin Hibbits uintptr_t err_irq_num; 710aeed3e9SJustin Hibbits uint8_t fm_id; 720aeed3e9SJustin Hibbits t_FmExceptionsCallback *exception_callback; 730aeed3e9SJustin Hibbits t_FmBusErrorCallback *bus_error_callback; 740aeed3e9SJustin Hibbits }; 750aeed3e9SJustin Hibbits 760aeed3e9SJustin Hibbits /** 770aeed3e9SJustin Hibbits * @group FMan private methods/members. 780aeed3e9SJustin Hibbits * @{ 790aeed3e9SJustin Hibbits */ 800aeed3e9SJustin Hibbits /** 810aeed3e9SJustin Hibbits * Frame Manager firmware. 820aeed3e9SJustin Hibbits * We use the same firmware for both P3041 and P2041 devices. 830aeed3e9SJustin Hibbits */ 840aeed3e9SJustin Hibbits const uint32_t fman_firmware[] = FMAN_UC_IMG; 850aeed3e9SJustin Hibbits const uint32_t fman_firmware_size = sizeof(fman_firmware); 860aeed3e9SJustin Hibbits static struct fman_softc *fm_sc = NULL; 870aeed3e9SJustin Hibbits 880aeed3e9SJustin Hibbits static t_Handle 890aeed3e9SJustin Hibbits fman_init(struct fman_softc *sc, struct fman_config *cfg) 900aeed3e9SJustin Hibbits { 910aeed3e9SJustin Hibbits t_FmParams fm_params; 920aeed3e9SJustin Hibbits t_Handle muram_handle, fm_handle; 930aeed3e9SJustin Hibbits t_Error error; 940aeed3e9SJustin Hibbits t_FmRevisionInfo revision_info; 950aeed3e9SJustin Hibbits uint16_t clock; 960aeed3e9SJustin Hibbits uint32_t tmp, mod; 970aeed3e9SJustin Hibbits 980aeed3e9SJustin Hibbits /* MURAM configuration */ 990aeed3e9SJustin Hibbits muram_handle = FM_MURAM_ConfigAndInit(cfg->mem_base_addr + 1000aeed3e9SJustin Hibbits FMAN_MURAM_OFF, FMAN_MURAM_SIZE); 1010aeed3e9SJustin Hibbits if (muram_handle == NULL) { 1020aeed3e9SJustin Hibbits device_printf(cfg->fman_device, "couldn't init FM MURAM module" 1030aeed3e9SJustin Hibbits "\n"); 1040aeed3e9SJustin Hibbits return (NULL); 1050aeed3e9SJustin Hibbits } 1060aeed3e9SJustin Hibbits sc->muram_handle = muram_handle; 1070aeed3e9SJustin Hibbits 1080aeed3e9SJustin Hibbits /* Fill in FM configuration */ 1090aeed3e9SJustin Hibbits fm_params.fmId = cfg->fm_id; 1100aeed3e9SJustin Hibbits /* XXX we support only one partition thus each fman has master id */ 1110aeed3e9SJustin Hibbits fm_params.guestId = NCSW_MASTER_ID; 1120aeed3e9SJustin Hibbits 1130aeed3e9SJustin Hibbits fm_params.baseAddr = cfg->mem_base_addr; 1140aeed3e9SJustin Hibbits fm_params.h_FmMuram = muram_handle; 1150aeed3e9SJustin Hibbits 1160aeed3e9SJustin Hibbits /* Get FMan clock in Hz */ 1170aeed3e9SJustin Hibbits if ((tmp = fman_get_clock(sc)) == 0) 1180aeed3e9SJustin Hibbits return (NULL); 1190aeed3e9SJustin Hibbits 1200aeed3e9SJustin Hibbits /* Convert FMan clock to MHz */ 1210aeed3e9SJustin Hibbits clock = (uint16_t)(tmp / 1000000); 1220aeed3e9SJustin Hibbits mod = tmp % 1000000; 1230aeed3e9SJustin Hibbits 1240aeed3e9SJustin Hibbits if (mod >= 500000) 1250aeed3e9SJustin Hibbits ++clock; 1260aeed3e9SJustin Hibbits 1270aeed3e9SJustin Hibbits fm_params.fmClkFreq = clock; 1280aeed3e9SJustin Hibbits fm_params.f_Exception = cfg->exception_callback; 1290aeed3e9SJustin Hibbits fm_params.f_BusError = cfg->bus_error_callback; 1300aeed3e9SJustin Hibbits fm_params.h_App = cfg->fman_device; 1310aeed3e9SJustin Hibbits fm_params.irq = cfg->irq_num; 1320aeed3e9SJustin Hibbits fm_params.errIrq = cfg->err_irq_num; 1330aeed3e9SJustin Hibbits 1340aeed3e9SJustin Hibbits fm_params.firmware.size = fman_firmware_size; 1350aeed3e9SJustin Hibbits fm_params.firmware.p_Code = (uint32_t*)fman_firmware; 1360aeed3e9SJustin Hibbits 1370aeed3e9SJustin Hibbits fm_handle = FM_Config(&fm_params); 1380aeed3e9SJustin Hibbits if (fm_handle == NULL) { 1390aeed3e9SJustin Hibbits device_printf(cfg->fman_device, "couldn't configure FM " 1400aeed3e9SJustin Hibbits "module\n"); 1410aeed3e9SJustin Hibbits goto err; 1420aeed3e9SJustin Hibbits } 1430aeed3e9SJustin Hibbits 1440aeed3e9SJustin Hibbits FM_ConfigResetOnInit(fm_handle, TRUE); 1450aeed3e9SJustin Hibbits 1460aeed3e9SJustin Hibbits error = FM_Init(fm_handle); 1470aeed3e9SJustin Hibbits if (error != E_OK) { 1480aeed3e9SJustin Hibbits device_printf(cfg->fman_device, "couldn't init FM module\n"); 1490aeed3e9SJustin Hibbits goto err2; 1500aeed3e9SJustin Hibbits } 1510aeed3e9SJustin Hibbits 1520aeed3e9SJustin Hibbits error = FM_GetRevision(fm_handle, &revision_info); 1530aeed3e9SJustin Hibbits if (error != E_OK) { 1540aeed3e9SJustin Hibbits device_printf(cfg->fman_device, "couldn't get FM revision\n"); 1550aeed3e9SJustin Hibbits goto err2; 1560aeed3e9SJustin Hibbits } 1570aeed3e9SJustin Hibbits 1580aeed3e9SJustin Hibbits device_printf(cfg->fman_device, "Hardware version: %d.%d.\n", 1590aeed3e9SJustin Hibbits revision_info.majorRev, revision_info.minorRev); 1600aeed3e9SJustin Hibbits 1610aeed3e9SJustin Hibbits return (fm_handle); 1620aeed3e9SJustin Hibbits 1630aeed3e9SJustin Hibbits err2: 1640aeed3e9SJustin Hibbits FM_Free(fm_handle); 1650aeed3e9SJustin Hibbits err: 1660aeed3e9SJustin Hibbits FM_MURAM_Free(muram_handle); 1670aeed3e9SJustin Hibbits return (NULL); 1680aeed3e9SJustin Hibbits } 1690aeed3e9SJustin Hibbits 1700aeed3e9SJustin Hibbits static void 1710aeed3e9SJustin Hibbits fman_exception_callback(t_Handle app_handle, e_FmExceptions exception) 1720aeed3e9SJustin Hibbits { 1730aeed3e9SJustin Hibbits struct fman_softc *sc; 1740aeed3e9SJustin Hibbits 1750aeed3e9SJustin Hibbits sc = app_handle; 1760aeed3e9SJustin Hibbits device_printf(sc->dev, "FMan exception occurred.\n"); 1770aeed3e9SJustin Hibbits } 1780aeed3e9SJustin Hibbits 1790aeed3e9SJustin Hibbits static void 1800aeed3e9SJustin Hibbits fman_error_callback(t_Handle app_handle, e_FmPortType port_type, 1810aeed3e9SJustin Hibbits uint8_t port_id, uint64_t addr, uint8_t tnum, uint16_t liodn) 1820aeed3e9SJustin Hibbits { 1830aeed3e9SJustin Hibbits struct fman_softc *sc; 1840aeed3e9SJustin Hibbits 1850aeed3e9SJustin Hibbits sc = app_handle; 1860aeed3e9SJustin Hibbits device_printf(sc->dev, "FMan error occurred.\n"); 1870aeed3e9SJustin Hibbits } 1880aeed3e9SJustin Hibbits /** @} */ 1890aeed3e9SJustin Hibbits 1900aeed3e9SJustin Hibbits 1910aeed3e9SJustin Hibbits /** 1920aeed3e9SJustin Hibbits * @group FMan driver interface. 1930aeed3e9SJustin Hibbits * @{ 1940aeed3e9SJustin Hibbits */ 1950aeed3e9SJustin Hibbits 1960aeed3e9SJustin Hibbits int 1970aeed3e9SJustin Hibbits fman_get_handle(t_Handle *fmh) 1980aeed3e9SJustin Hibbits { 1990aeed3e9SJustin Hibbits 2000aeed3e9SJustin Hibbits if (fm_sc == NULL) 2010aeed3e9SJustin Hibbits return (ENOMEM); 2020aeed3e9SJustin Hibbits 2030aeed3e9SJustin Hibbits *fmh = fm_sc->fm_handle; 2040aeed3e9SJustin Hibbits 2050aeed3e9SJustin Hibbits return (0); 2060aeed3e9SJustin Hibbits } 2070aeed3e9SJustin Hibbits 2080aeed3e9SJustin Hibbits int 2090aeed3e9SJustin Hibbits fman_get_muram_handle(t_Handle *muramh) 2100aeed3e9SJustin Hibbits { 2110aeed3e9SJustin Hibbits 2120aeed3e9SJustin Hibbits if (fm_sc == NULL) 2130aeed3e9SJustin Hibbits return (ENOMEM); 2140aeed3e9SJustin Hibbits 2150aeed3e9SJustin Hibbits *muramh = fm_sc->muram_handle; 2160aeed3e9SJustin Hibbits 2170aeed3e9SJustin Hibbits return (0); 2180aeed3e9SJustin Hibbits } 2190aeed3e9SJustin Hibbits 2200aeed3e9SJustin Hibbits int 2210aeed3e9SJustin Hibbits fman_get_bushandle(vm_offset_t *fm_base) 2220aeed3e9SJustin Hibbits { 2230aeed3e9SJustin Hibbits 2240aeed3e9SJustin Hibbits if (fm_sc == NULL) 2250aeed3e9SJustin Hibbits return (ENOMEM); 2260aeed3e9SJustin Hibbits 2270aeed3e9SJustin Hibbits *fm_base = rman_get_bushandle(fm_sc->mem_res); 2280aeed3e9SJustin Hibbits 2290aeed3e9SJustin Hibbits return (0); 2300aeed3e9SJustin Hibbits } 2310aeed3e9SJustin Hibbits 2320aeed3e9SJustin Hibbits int 2330aeed3e9SJustin Hibbits fman_attach(device_t dev) 2340aeed3e9SJustin Hibbits { 2350aeed3e9SJustin Hibbits struct fman_softc *sc; 2360aeed3e9SJustin Hibbits struct fman_config cfg; 2370aeed3e9SJustin Hibbits 2380aeed3e9SJustin Hibbits sc = device_get_softc(dev); 2390aeed3e9SJustin Hibbits sc->dev = dev; 2400aeed3e9SJustin Hibbits fm_sc = sc; 2410aeed3e9SJustin Hibbits 2420aeed3e9SJustin Hibbits /* Check if MallocSmart allocator is ready */ 2430aeed3e9SJustin Hibbits if (XX_MallocSmartInit() != E_OK) { 2440aeed3e9SJustin Hibbits device_printf(dev, "could not initialize smart allocator.\n"); 2450aeed3e9SJustin Hibbits return (ENXIO); 2460aeed3e9SJustin Hibbits } 2470aeed3e9SJustin Hibbits 2480aeed3e9SJustin Hibbits XX_TrackInit(); 2490aeed3e9SJustin Hibbits 2500aeed3e9SJustin Hibbits sc->mem_rid = 0; 2510aeed3e9SJustin Hibbits sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 2520aeed3e9SJustin Hibbits RF_ACTIVE); 2530aeed3e9SJustin Hibbits if (!sc->mem_res) { 2540aeed3e9SJustin Hibbits device_printf(dev, "could not allocate memory.\n"); 2550aeed3e9SJustin Hibbits return (ENXIO); 2560aeed3e9SJustin Hibbits } 2570aeed3e9SJustin Hibbits 2580aeed3e9SJustin Hibbits sc->irq_rid = 0; 2590aeed3e9SJustin Hibbits sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 2600aeed3e9SJustin Hibbits RF_ACTIVE); 2610aeed3e9SJustin Hibbits if (!sc->irq_res) { 2620aeed3e9SJustin Hibbits device_printf(dev, "could not allocate interrupt.\n"); 2630aeed3e9SJustin Hibbits goto err; 2640aeed3e9SJustin Hibbits } 2650aeed3e9SJustin Hibbits 2660aeed3e9SJustin Hibbits /* 2670aeed3e9SJustin Hibbits * XXX: Fix FMan interrupt. This is workaround for the issue with 2680aeed3e9SJustin Hibbits * interrupts directed to multiple CPUs by the interrupts subsystem. 2690aeed3e9SJustin Hibbits * Workaround is to bind the interrupt to only one CPU0. 2700aeed3e9SJustin Hibbits */ 2710aeed3e9SJustin Hibbits XX_FmanFixIntr(rman_get_start(sc->irq_res)); 2720aeed3e9SJustin Hibbits 2730aeed3e9SJustin Hibbits sc->err_irq_rid = 1; 2740aeed3e9SJustin Hibbits sc->err_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 2750aeed3e9SJustin Hibbits &sc->err_irq_rid, RF_ACTIVE | RF_SHAREABLE); 2760aeed3e9SJustin Hibbits if (!sc->err_irq_res) { 2770aeed3e9SJustin Hibbits device_printf(dev, "could not allocate error interrupt.\n"); 2780aeed3e9SJustin Hibbits goto err; 2790aeed3e9SJustin Hibbits } 2800aeed3e9SJustin Hibbits 2810aeed3e9SJustin Hibbits /* Set FMan configuration */ 2820aeed3e9SJustin Hibbits cfg.fman_device = dev; 2830aeed3e9SJustin Hibbits cfg.fm_id = device_get_unit(dev); 2840aeed3e9SJustin Hibbits cfg.mem_base_addr = rman_get_bushandle(sc->mem_res); 285*f77405e3SJustin Hibbits cfg.irq_num = (uintptr_t)sc->irq_res; 286*f77405e3SJustin Hibbits cfg.err_irq_num = (uintptr_t)sc->err_irq_res; 2870aeed3e9SJustin Hibbits cfg.exception_callback = fman_exception_callback; 2880aeed3e9SJustin Hibbits cfg.bus_error_callback = fman_error_callback; 2890aeed3e9SJustin Hibbits 2900aeed3e9SJustin Hibbits sc->fm_handle = fman_init(sc, &cfg); 2910aeed3e9SJustin Hibbits if (sc->fm_handle == NULL) { 2920aeed3e9SJustin Hibbits device_printf(dev, "could not be configured\n"); 2930aeed3e9SJustin Hibbits return (ENXIO); 2940aeed3e9SJustin Hibbits } 2950aeed3e9SJustin Hibbits 2960aeed3e9SJustin Hibbits return (bus_generic_attach(dev)); 2970aeed3e9SJustin Hibbits 2980aeed3e9SJustin Hibbits err: 2990aeed3e9SJustin Hibbits fman_detach(dev); 3000aeed3e9SJustin Hibbits return (ENXIO); 3010aeed3e9SJustin Hibbits } 3020aeed3e9SJustin Hibbits 3030aeed3e9SJustin Hibbits int 3040aeed3e9SJustin Hibbits fman_detach(device_t dev) 3050aeed3e9SJustin Hibbits { 3060aeed3e9SJustin Hibbits struct fman_softc *sc; 3070aeed3e9SJustin Hibbits 3080aeed3e9SJustin Hibbits sc = device_get_softc(dev); 3090aeed3e9SJustin Hibbits 3100aeed3e9SJustin Hibbits if (sc->muram_handle) { 3110aeed3e9SJustin Hibbits FM_MURAM_Free(sc->muram_handle); 3120aeed3e9SJustin Hibbits } 3130aeed3e9SJustin Hibbits 3140aeed3e9SJustin Hibbits if (sc->fm_handle) { 3150aeed3e9SJustin Hibbits FM_Free(sc->fm_handle); 3160aeed3e9SJustin Hibbits } 3170aeed3e9SJustin Hibbits 3180aeed3e9SJustin Hibbits if (sc->mem_res) { 3190aeed3e9SJustin Hibbits bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, 3200aeed3e9SJustin Hibbits sc->mem_res); 3210aeed3e9SJustin Hibbits } 3220aeed3e9SJustin Hibbits 3230aeed3e9SJustin Hibbits if (sc->irq_res) { 3240aeed3e9SJustin Hibbits bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 3250aeed3e9SJustin Hibbits sc->irq_res); 3260aeed3e9SJustin Hibbits } 3270aeed3e9SJustin Hibbits 3280aeed3e9SJustin Hibbits if (sc->irq_res) { 3290aeed3e9SJustin Hibbits bus_release_resource(dev, SYS_RES_IRQ, sc->err_irq_rid, 3300aeed3e9SJustin Hibbits sc->err_irq_res); 3310aeed3e9SJustin Hibbits } 3320aeed3e9SJustin Hibbits 3330aeed3e9SJustin Hibbits return (0); 3340aeed3e9SJustin Hibbits } 3350aeed3e9SJustin Hibbits 3360aeed3e9SJustin Hibbits int 3370aeed3e9SJustin Hibbits fman_suspend(device_t dev) 3380aeed3e9SJustin Hibbits { 3390aeed3e9SJustin Hibbits 3400aeed3e9SJustin Hibbits return (0); 3410aeed3e9SJustin Hibbits } 3420aeed3e9SJustin Hibbits 3430aeed3e9SJustin Hibbits int 3440aeed3e9SJustin Hibbits fman_resume(device_t dev) 3450aeed3e9SJustin Hibbits { 3460aeed3e9SJustin Hibbits 3470aeed3e9SJustin Hibbits return (0); 3480aeed3e9SJustin Hibbits } 3490aeed3e9SJustin Hibbits 3500aeed3e9SJustin Hibbits int 3510aeed3e9SJustin Hibbits fman_shutdown(device_t dev) 3520aeed3e9SJustin Hibbits { 3530aeed3e9SJustin Hibbits 3540aeed3e9SJustin Hibbits return (0); 3550aeed3e9SJustin Hibbits } 3560aeed3e9SJustin Hibbits 3570aeed3e9SJustin Hibbits /** @} */ 358