162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PS3 system bus driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2006 Sony Computer Entertainment Inc. 662306a36Sopenharmony_ci * Copyright 2006 Sony Corp. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/export.h> 1262306a36Sopenharmony_ci#include <linux/dma-map-ops.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/udbg.h> 1762306a36Sopenharmony_ci#include <asm/lv1call.h> 1862306a36Sopenharmony_ci#include <asm/firmware.h> 1962306a36Sopenharmony_ci#include <asm/cell-regs.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "platform.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic struct device ps3_system_bus = { 2462306a36Sopenharmony_ci .init_name = "ps3_system", 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* FIXME: need device usage counters! */ 2862306a36Sopenharmony_cistatic struct { 2962306a36Sopenharmony_ci struct mutex mutex; 3062306a36Sopenharmony_ci int sb_11; /* usb 0 */ 3162306a36Sopenharmony_ci int sb_12; /* usb 0 */ 3262306a36Sopenharmony_ci int gpu; 3362306a36Sopenharmony_ci} usage_hack; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int ps3_is_device(struct ps3_system_bus_device *dev, u64 bus_id, 3662306a36Sopenharmony_ci u64 dev_id) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci return dev->bus_id == bus_id && dev->dev_id == dev_id; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int ps3_open_hv_device_sb(struct ps3_system_bus_device *dev) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci int result; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci BUG_ON(!dev->bus_id); 4662306a36Sopenharmony_ci mutex_lock(&usage_hack.mutex); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (ps3_is_device(dev, 1, 1)) { 4962306a36Sopenharmony_ci usage_hack.sb_11++; 5062306a36Sopenharmony_ci if (usage_hack.sb_11 > 1) { 5162306a36Sopenharmony_ci result = 0; 5262306a36Sopenharmony_ci goto done; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (ps3_is_device(dev, 1, 2)) { 5762306a36Sopenharmony_ci usage_hack.sb_12++; 5862306a36Sopenharmony_ci if (usage_hack.sb_12 > 1) { 5962306a36Sopenharmony_ci result = 0; 6062306a36Sopenharmony_ci goto done; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci result = lv1_open_device(dev->bus_id, dev->dev_id, 0); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (result) { 6762306a36Sopenharmony_ci pr_warn("%s:%d: lv1_open_device dev=%u.%u(%s) failed: %s\n", 6862306a36Sopenharmony_ci __func__, __LINE__, dev->match_id, dev->match_sub_id, 6962306a36Sopenharmony_ci dev_name(&dev->core), ps3_result(result)); 7062306a36Sopenharmony_ci result = -EPERM; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cidone: 7462306a36Sopenharmony_ci mutex_unlock(&usage_hack.mutex); 7562306a36Sopenharmony_ci return result; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int ps3_close_hv_device_sb(struct ps3_system_bus_device *dev) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci int result; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci BUG_ON(!dev->bus_id); 8362306a36Sopenharmony_ci mutex_lock(&usage_hack.mutex); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (ps3_is_device(dev, 1, 1)) { 8662306a36Sopenharmony_ci usage_hack.sb_11--; 8762306a36Sopenharmony_ci if (usage_hack.sb_11) { 8862306a36Sopenharmony_ci result = 0; 8962306a36Sopenharmony_ci goto done; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (ps3_is_device(dev, 1, 2)) { 9462306a36Sopenharmony_ci usage_hack.sb_12--; 9562306a36Sopenharmony_ci if (usage_hack.sb_12) { 9662306a36Sopenharmony_ci result = 0; 9762306a36Sopenharmony_ci goto done; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci result = lv1_close_device(dev->bus_id, dev->dev_id); 10262306a36Sopenharmony_ci BUG_ON(result); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cidone: 10562306a36Sopenharmony_ci mutex_unlock(&usage_hack.mutex); 10662306a36Sopenharmony_ci return result; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int ps3_open_hv_device_gpu(struct ps3_system_bus_device *dev) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci int result; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci mutex_lock(&usage_hack.mutex); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci usage_hack.gpu++; 11662306a36Sopenharmony_ci if (usage_hack.gpu > 1) { 11762306a36Sopenharmony_ci result = 0; 11862306a36Sopenharmony_ci goto done; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci result = lv1_gpu_open(0); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (result) { 12462306a36Sopenharmony_ci pr_warn("%s:%d: lv1_gpu_open failed: %s\n", __func__, 12562306a36Sopenharmony_ci __LINE__, ps3_result(result)); 12662306a36Sopenharmony_ci result = -EPERM; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cidone: 13062306a36Sopenharmony_ci mutex_unlock(&usage_hack.mutex); 13162306a36Sopenharmony_ci return result; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int ps3_close_hv_device_gpu(struct ps3_system_bus_device *dev) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci int result; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci mutex_lock(&usage_hack.mutex); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci usage_hack.gpu--; 14162306a36Sopenharmony_ci if (usage_hack.gpu) { 14262306a36Sopenharmony_ci result = 0; 14362306a36Sopenharmony_ci goto done; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci result = lv1_gpu_close(); 14762306a36Sopenharmony_ci BUG_ON(result); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cidone: 15062306a36Sopenharmony_ci mutex_unlock(&usage_hack.mutex); 15162306a36Sopenharmony_ci return result; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciint ps3_open_hv_device(struct ps3_system_bus_device *dev) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci BUG_ON(!dev); 15762306a36Sopenharmony_ci pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci switch (dev->match_id) { 16062306a36Sopenharmony_ci case PS3_MATCH_ID_EHCI: 16162306a36Sopenharmony_ci case PS3_MATCH_ID_OHCI: 16262306a36Sopenharmony_ci case PS3_MATCH_ID_GELIC: 16362306a36Sopenharmony_ci case PS3_MATCH_ID_STOR_DISK: 16462306a36Sopenharmony_ci case PS3_MATCH_ID_STOR_ROM: 16562306a36Sopenharmony_ci case PS3_MATCH_ID_STOR_FLASH: 16662306a36Sopenharmony_ci return ps3_open_hv_device_sb(dev); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci case PS3_MATCH_ID_SOUND: 16962306a36Sopenharmony_ci case PS3_MATCH_ID_GPU: 17062306a36Sopenharmony_ci return ps3_open_hv_device_gpu(dev); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci case PS3_MATCH_ID_AV_SETTINGS: 17362306a36Sopenharmony_ci case PS3_MATCH_ID_SYSTEM_MANAGER: 17462306a36Sopenharmony_ci pr_debug("%s:%d: unsupported match_id: %u\n", __func__, 17562306a36Sopenharmony_ci __LINE__, dev->match_id); 17662306a36Sopenharmony_ci pr_debug("%s:%d: bus_id: %llu\n", __func__, __LINE__, 17762306a36Sopenharmony_ci dev->bus_id); 17862306a36Sopenharmony_ci BUG(); 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci default: 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__, 18662306a36Sopenharmony_ci dev->match_id); 18762306a36Sopenharmony_ci BUG(); 18862306a36Sopenharmony_ci return -ENODEV; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_open_hv_device); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciint ps3_close_hv_device(struct ps3_system_bus_device *dev) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci BUG_ON(!dev); 19562306a36Sopenharmony_ci pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci switch (dev->match_id) { 19862306a36Sopenharmony_ci case PS3_MATCH_ID_EHCI: 19962306a36Sopenharmony_ci case PS3_MATCH_ID_OHCI: 20062306a36Sopenharmony_ci case PS3_MATCH_ID_GELIC: 20162306a36Sopenharmony_ci case PS3_MATCH_ID_STOR_DISK: 20262306a36Sopenharmony_ci case PS3_MATCH_ID_STOR_ROM: 20362306a36Sopenharmony_ci case PS3_MATCH_ID_STOR_FLASH: 20462306a36Sopenharmony_ci return ps3_close_hv_device_sb(dev); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci case PS3_MATCH_ID_SOUND: 20762306a36Sopenharmony_ci case PS3_MATCH_ID_GPU: 20862306a36Sopenharmony_ci return ps3_close_hv_device_gpu(dev); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci case PS3_MATCH_ID_AV_SETTINGS: 21162306a36Sopenharmony_ci case PS3_MATCH_ID_SYSTEM_MANAGER: 21262306a36Sopenharmony_ci pr_debug("%s:%d: unsupported match_id: %u\n", __func__, 21362306a36Sopenharmony_ci __LINE__, dev->match_id); 21462306a36Sopenharmony_ci pr_debug("%s:%d: bus_id: %llu\n", __func__, __LINE__, 21562306a36Sopenharmony_ci dev->bus_id); 21662306a36Sopenharmony_ci BUG(); 21762306a36Sopenharmony_ci return -EINVAL; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci default: 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__, 22462306a36Sopenharmony_ci dev->match_id); 22562306a36Sopenharmony_ci BUG(); 22662306a36Sopenharmony_ci return -ENODEV; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_close_hv_device); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) 23162306a36Sopenharmony_cistatic void _dump_mmio_region(const struct ps3_mmio_region* r, 23262306a36Sopenharmony_ci const char* func, int line) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci pr_debug("%s:%d: dev %llu:%llu\n", func, line, r->dev->bus_id, 23562306a36Sopenharmony_ci r->dev->dev_id); 23662306a36Sopenharmony_ci pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); 23762306a36Sopenharmony_ci pr_debug("%s:%d: len %lxh\n", func, line, r->len); 23862306a36Sopenharmony_ci pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int ps3_sb_mmio_region_create(struct ps3_mmio_region *r) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci int result; 24462306a36Sopenharmony_ci u64 lpar_addr; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci result = lv1_map_device_mmio_region(r->dev->bus_id, r->dev->dev_id, 24762306a36Sopenharmony_ci r->bus_addr, r->len, r->page_size, &lpar_addr); 24862306a36Sopenharmony_ci r->lpar_addr = lpar_addr; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (result) { 25162306a36Sopenharmony_ci pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n", 25262306a36Sopenharmony_ci __func__, __LINE__, ps3_result(result)); 25362306a36Sopenharmony_ci r->lpar_addr = 0; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci dump_mmio_region(r); 25762306a36Sopenharmony_ci return result; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int ps3_ioc0_mmio_region_create(struct ps3_mmio_region *r) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci /* device specific; do nothing currently */ 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ciint ps3_mmio_region_create(struct ps3_mmio_region *r) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci return r->mmio_ops->create(r); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_mmio_region_create); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int ps3_sb_free_mmio_region(struct ps3_mmio_region *r) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci int result; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci dump_mmio_region(r); 27762306a36Sopenharmony_ci result = lv1_unmap_device_mmio_region(r->dev->bus_id, r->dev->dev_id, 27862306a36Sopenharmony_ci r->lpar_addr); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (result) 28162306a36Sopenharmony_ci pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n", 28262306a36Sopenharmony_ci __func__, __LINE__, ps3_result(result)); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci r->lpar_addr = 0; 28562306a36Sopenharmony_ci return result; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int ps3_ioc0_free_mmio_region(struct ps3_mmio_region *r) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci /* device specific; do nothing currently */ 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciint ps3_free_mmio_region(struct ps3_mmio_region *r) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return r->mmio_ops->free(r); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_free_mmio_region); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic const struct ps3_mmio_region_ops ps3_mmio_sb_region_ops = { 30362306a36Sopenharmony_ci .create = ps3_sb_mmio_region_create, 30462306a36Sopenharmony_ci .free = ps3_sb_free_mmio_region 30562306a36Sopenharmony_ci}; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic const struct ps3_mmio_region_ops ps3_mmio_ioc0_region_ops = { 30862306a36Sopenharmony_ci .create = ps3_ioc0_mmio_region_create, 30962306a36Sopenharmony_ci .free = ps3_ioc0_free_mmio_region 31062306a36Sopenharmony_ci}; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ciint ps3_mmio_region_init(struct ps3_system_bus_device *dev, 31362306a36Sopenharmony_ci struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len, 31462306a36Sopenharmony_ci enum ps3_mmio_page_size page_size) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci r->dev = dev; 31762306a36Sopenharmony_ci r->bus_addr = bus_addr; 31862306a36Sopenharmony_ci r->len = len; 31962306a36Sopenharmony_ci r->page_size = page_size; 32062306a36Sopenharmony_ci switch (dev->dev_type) { 32162306a36Sopenharmony_ci case PS3_DEVICE_TYPE_SB: 32262306a36Sopenharmony_ci r->mmio_ops = &ps3_mmio_sb_region_ops; 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci case PS3_DEVICE_TYPE_IOC0: 32562306a36Sopenharmony_ci r->mmio_ops = &ps3_mmio_ioc0_region_ops; 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci default: 32862306a36Sopenharmony_ci BUG(); 32962306a36Sopenharmony_ci return -EINVAL; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_mmio_region_init); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int ps3_system_bus_match(struct device *_dev, 33662306a36Sopenharmony_ci struct device_driver *_drv) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci int result; 33962306a36Sopenharmony_ci struct ps3_system_bus_driver *drv = ps3_drv_to_system_bus_drv(_drv); 34062306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (!dev->match_sub_id) 34362306a36Sopenharmony_ci result = dev->match_id == drv->match_id; 34462306a36Sopenharmony_ci else 34562306a36Sopenharmony_ci result = dev->match_sub_id == drv->match_sub_id && 34662306a36Sopenharmony_ci dev->match_id == drv->match_id; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (result) 34962306a36Sopenharmony_ci pr_info("%s:%d: dev=%u.%u(%s), drv=%u.%u(%s): match\n", 35062306a36Sopenharmony_ci __func__, __LINE__, 35162306a36Sopenharmony_ci dev->match_id, dev->match_sub_id, dev_name(&dev->core), 35262306a36Sopenharmony_ci drv->match_id, drv->match_sub_id, drv->core.name); 35362306a36Sopenharmony_ci else 35462306a36Sopenharmony_ci pr_debug("%s:%d: dev=%u.%u(%s), drv=%u.%u(%s): miss\n", 35562306a36Sopenharmony_ci __func__, __LINE__, 35662306a36Sopenharmony_ci dev->match_id, dev->match_sub_id, dev_name(&dev->core), 35762306a36Sopenharmony_ci drv->match_id, drv->match_sub_id, drv->core.name); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return result; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic int ps3_system_bus_probe(struct device *_dev) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci int result = 0; 36562306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 36662306a36Sopenharmony_ci struct ps3_system_bus_driver *drv; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci BUG_ON(!dev); 36962306a36Sopenharmony_ci dev_dbg(_dev, "%s:%d\n", __func__, __LINE__); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci drv = ps3_system_bus_dev_to_system_bus_drv(dev); 37262306a36Sopenharmony_ci BUG_ON(!drv); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (drv->probe) 37562306a36Sopenharmony_ci result = drv->probe(dev); 37662306a36Sopenharmony_ci else 37762306a36Sopenharmony_ci pr_debug("%s:%d: %s no probe method\n", __func__, __LINE__, 37862306a36Sopenharmony_ci dev_name(&dev->core)); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core)); 38162306a36Sopenharmony_ci return result; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic void ps3_system_bus_remove(struct device *_dev) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 38762306a36Sopenharmony_ci struct ps3_system_bus_driver *drv; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci BUG_ON(!dev); 39062306a36Sopenharmony_ci dev_dbg(_dev, "%s:%d\n", __func__, __LINE__); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci drv = ps3_system_bus_dev_to_system_bus_drv(dev); 39362306a36Sopenharmony_ci BUG_ON(!drv); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (drv->remove) 39662306a36Sopenharmony_ci drv->remove(dev); 39762306a36Sopenharmony_ci else 39862306a36Sopenharmony_ci dev_dbg(&dev->core, "%s:%d %s: no remove method\n", 39962306a36Sopenharmony_ci __func__, __LINE__, drv->core.name); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core)); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic void ps3_system_bus_shutdown(struct device *_dev) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 40762306a36Sopenharmony_ci struct ps3_system_bus_driver *drv; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci BUG_ON(!dev); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, 41262306a36Sopenharmony_ci dev->match_id); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!dev->core.driver) { 41562306a36Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, 41662306a36Sopenharmony_ci __LINE__); 41762306a36Sopenharmony_ci return; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci drv = ps3_system_bus_dev_to_system_bus_drv(dev); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci BUG_ON(!drv); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__, 42562306a36Sopenharmony_ci dev_name(&dev->core), drv->core.name); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (drv->shutdown) 42862306a36Sopenharmony_ci drv->shutdown(dev); 42962306a36Sopenharmony_ci else if (drv->remove) { 43062306a36Sopenharmony_ci dev_dbg(&dev->core, "%s:%d %s: no shutdown, calling remove\n", 43162306a36Sopenharmony_ci __func__, __LINE__, drv->core.name); 43262306a36Sopenharmony_ci drv->remove(dev); 43362306a36Sopenharmony_ci } else { 43462306a36Sopenharmony_ci dev_dbg(&dev->core, "%s:%d %s: no shutdown method\n", 43562306a36Sopenharmony_ci __func__, __LINE__, drv->core.name); 43662306a36Sopenharmony_ci BUG(); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int ps3_system_bus_uevent(const struct device *_dev, struct kobj_uevent_env *env) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (add_uevent_var(env, "MODALIAS=ps3:%d:%d", dev->match_id, 44762306a36Sopenharmony_ci dev->match_sub_id)) 44862306a36Sopenharmony_ci return -ENOMEM; 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *_dev, struct device_attribute *a, 45362306a36Sopenharmony_ci char *buf) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 45662306a36Sopenharmony_ci int len = snprintf(buf, PAGE_SIZE, "ps3:%d:%d\n", dev->match_id, 45762306a36Sopenharmony_ci dev->match_sub_id); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic struct attribute *ps3_system_bus_dev_attrs[] = { 46462306a36Sopenharmony_ci &dev_attr_modalias.attr, 46562306a36Sopenharmony_ci NULL, 46662306a36Sopenharmony_ci}; 46762306a36Sopenharmony_ciATTRIBUTE_GROUPS(ps3_system_bus_dev); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic struct bus_type ps3_system_bus_type = { 47062306a36Sopenharmony_ci .name = "ps3_system_bus", 47162306a36Sopenharmony_ci .match = ps3_system_bus_match, 47262306a36Sopenharmony_ci .uevent = ps3_system_bus_uevent, 47362306a36Sopenharmony_ci .probe = ps3_system_bus_probe, 47462306a36Sopenharmony_ci .remove = ps3_system_bus_remove, 47562306a36Sopenharmony_ci .shutdown = ps3_system_bus_shutdown, 47662306a36Sopenharmony_ci .dev_groups = ps3_system_bus_dev_groups, 47762306a36Sopenharmony_ci}; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int __init ps3_system_bus_init(void) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci int result; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 48462306a36Sopenharmony_ci return -ENODEV; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci pr_debug(" -> %s:%d\n", __func__, __LINE__); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci mutex_init(&usage_hack.mutex); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci result = device_register(&ps3_system_bus); 49162306a36Sopenharmony_ci BUG_ON(result); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci result = bus_register(&ps3_system_bus_type); 49462306a36Sopenharmony_ci BUG_ON(result); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci pr_debug(" <- %s:%d\n", __func__, __LINE__); 49762306a36Sopenharmony_ci return result; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cicore_initcall(ps3_system_bus_init); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci/* Allocates a contiguous real buffer and creates mappings over it. 50362306a36Sopenharmony_ci * Returns the virtual address of the buffer and sets dma_handle 50462306a36Sopenharmony_ci * to the dma address (mapping) of the first page. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_cistatic void * ps3_alloc_coherent(struct device *_dev, size_t size, 50762306a36Sopenharmony_ci dma_addr_t *dma_handle, gfp_t flag, 50862306a36Sopenharmony_ci unsigned long attrs) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci int result; 51162306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 51262306a36Sopenharmony_ci unsigned long virt_addr; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci flag &= ~(__GFP_DMA | __GFP_HIGHMEM); 51562306a36Sopenharmony_ci flag |= __GFP_ZERO; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci virt_addr = __get_free_pages(flag, get_order(size)); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (!virt_addr) { 52062306a36Sopenharmony_ci pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__); 52162306a36Sopenharmony_ci goto clean_none; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle, 52562306a36Sopenharmony_ci CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | 52662306a36Sopenharmony_ci CBE_IOPTE_SO_RW | CBE_IOPTE_M); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (result) { 52962306a36Sopenharmony_ci pr_debug("%s:%d: ps3_dma_map failed (%d)\n", 53062306a36Sopenharmony_ci __func__, __LINE__, result); 53162306a36Sopenharmony_ci BUG_ON("check region type"); 53262306a36Sopenharmony_ci goto clean_alloc; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return (void*)virt_addr; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ciclean_alloc: 53862306a36Sopenharmony_ci free_pages(virt_addr, get_order(size)); 53962306a36Sopenharmony_ciclean_none: 54062306a36Sopenharmony_ci dma_handle = NULL; 54162306a36Sopenharmony_ci return NULL; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, 54562306a36Sopenharmony_ci dma_addr_t dma_handle, unsigned long attrs) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci ps3_dma_unmap(dev->d_region, dma_handle, size); 55062306a36Sopenharmony_ci free_pages((unsigned long)vaddr, get_order(size)); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/* Creates TCEs for a user provided buffer. The user buffer must be 55462306a36Sopenharmony_ci * contiguous real kernel storage (not vmalloc). The address passed here 55562306a36Sopenharmony_ci * comprises a page address and offset into that page. The dma_addr_t 55662306a36Sopenharmony_ci * returned will point to the same byte within the page as was passed in. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page, 56062306a36Sopenharmony_ci unsigned long offset, size_t size, enum dma_data_direction direction, 56162306a36Sopenharmony_ci unsigned long attrs) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 56462306a36Sopenharmony_ci int result; 56562306a36Sopenharmony_ci dma_addr_t bus_addr; 56662306a36Sopenharmony_ci void *ptr = page_address(page) + offset; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, 56962306a36Sopenharmony_ci &bus_addr, 57062306a36Sopenharmony_ci CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | 57162306a36Sopenharmony_ci CBE_IOPTE_SO_RW | CBE_IOPTE_M); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (result) { 57462306a36Sopenharmony_ci pr_debug("%s:%d: ps3_dma_map failed (%d)\n", 57562306a36Sopenharmony_ci __func__, __LINE__, result); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci return bus_addr; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page, 58262306a36Sopenharmony_ci unsigned long offset, size_t size, 58362306a36Sopenharmony_ci enum dma_data_direction direction, 58462306a36Sopenharmony_ci unsigned long attrs) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 58762306a36Sopenharmony_ci int result; 58862306a36Sopenharmony_ci dma_addr_t bus_addr; 58962306a36Sopenharmony_ci u64 iopte_flag; 59062306a36Sopenharmony_ci void *ptr = page_address(page) + offset; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci iopte_flag = CBE_IOPTE_M; 59362306a36Sopenharmony_ci switch (direction) { 59462306a36Sopenharmony_ci case DMA_BIDIRECTIONAL: 59562306a36Sopenharmony_ci iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW; 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci case DMA_TO_DEVICE: 59862306a36Sopenharmony_ci iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_SO_R; 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci case DMA_FROM_DEVICE: 60162306a36Sopenharmony_ci iopte_flag |= CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW; 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci default: 60462306a36Sopenharmony_ci /* not happened */ 60562306a36Sopenharmony_ci BUG(); 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, 60862306a36Sopenharmony_ci &bus_addr, iopte_flag); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (result) { 61162306a36Sopenharmony_ci pr_debug("%s:%d: ps3_dma_map failed (%d)\n", 61262306a36Sopenharmony_ci __func__, __LINE__, result); 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci return bus_addr; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic void ps3_unmap_page(struct device *_dev, dma_addr_t dma_addr, 61862306a36Sopenharmony_ci size_t size, enum dma_data_direction direction, unsigned long attrs) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 62162306a36Sopenharmony_ci int result; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci result = ps3_dma_unmap(dev->d_region, dma_addr, size); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (result) { 62662306a36Sopenharmony_ci pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n", 62762306a36Sopenharmony_ci __func__, __LINE__, result); 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl, 63262306a36Sopenharmony_ci int nents, enum dma_data_direction direction, unsigned long attrs) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci#if defined(CONFIG_PS3_DYNAMIC_DMA) 63562306a36Sopenharmony_ci BUG_ON("do"); 63662306a36Sopenharmony_ci return -EPERM; 63762306a36Sopenharmony_ci#else 63862306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 63962306a36Sopenharmony_ci struct scatterlist *sg; 64062306a36Sopenharmony_ci int i; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci for_each_sg(sgl, sg, nents, i) { 64362306a36Sopenharmony_ci int result = ps3_dma_map(dev->d_region, sg_phys(sg), 64462306a36Sopenharmony_ci sg->length, &sg->dma_address, 0); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (result) { 64762306a36Sopenharmony_ci pr_debug("%s:%d: ps3_dma_map failed (%d)\n", 64862306a36Sopenharmony_ci __func__, __LINE__, result); 64962306a36Sopenharmony_ci return -EINVAL; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci sg->dma_length = sg->length; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return nents; 65662306a36Sopenharmony_ci#endif 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, 66062306a36Sopenharmony_ci int nents, 66162306a36Sopenharmony_ci enum dma_data_direction direction, 66262306a36Sopenharmony_ci unsigned long attrs) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci BUG(); 66562306a36Sopenharmony_ci return -EINVAL; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg, 66962306a36Sopenharmony_ci int nents, enum dma_data_direction direction, unsigned long attrs) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci#if defined(CONFIG_PS3_DYNAMIC_DMA) 67262306a36Sopenharmony_ci BUG_ON("do"); 67362306a36Sopenharmony_ci#endif 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg, 67762306a36Sopenharmony_ci int nents, enum dma_data_direction direction, 67862306a36Sopenharmony_ci unsigned long attrs) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci BUG(); 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int ps3_dma_supported(struct device *_dev, u64 mask) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci return mask >= DMA_BIT_MASK(32); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic const struct dma_map_ops ps3_sb_dma_ops = { 68962306a36Sopenharmony_ci .alloc = ps3_alloc_coherent, 69062306a36Sopenharmony_ci .free = ps3_free_coherent, 69162306a36Sopenharmony_ci .map_sg = ps3_sb_map_sg, 69262306a36Sopenharmony_ci .unmap_sg = ps3_sb_unmap_sg, 69362306a36Sopenharmony_ci .dma_supported = ps3_dma_supported, 69462306a36Sopenharmony_ci .map_page = ps3_sb_map_page, 69562306a36Sopenharmony_ci .unmap_page = ps3_unmap_page, 69662306a36Sopenharmony_ci .mmap = dma_common_mmap, 69762306a36Sopenharmony_ci .get_sgtable = dma_common_get_sgtable, 69862306a36Sopenharmony_ci .alloc_pages = dma_common_alloc_pages, 69962306a36Sopenharmony_ci .free_pages = dma_common_free_pages, 70062306a36Sopenharmony_ci}; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic const struct dma_map_ops ps3_ioc0_dma_ops = { 70362306a36Sopenharmony_ci .alloc = ps3_alloc_coherent, 70462306a36Sopenharmony_ci .free = ps3_free_coherent, 70562306a36Sopenharmony_ci .map_sg = ps3_ioc0_map_sg, 70662306a36Sopenharmony_ci .unmap_sg = ps3_ioc0_unmap_sg, 70762306a36Sopenharmony_ci .dma_supported = ps3_dma_supported, 70862306a36Sopenharmony_ci .map_page = ps3_ioc0_map_page, 70962306a36Sopenharmony_ci .unmap_page = ps3_unmap_page, 71062306a36Sopenharmony_ci .mmap = dma_common_mmap, 71162306a36Sopenharmony_ci .get_sgtable = dma_common_get_sgtable, 71262306a36Sopenharmony_ci .alloc_pages = dma_common_alloc_pages, 71362306a36Sopenharmony_ci .free_pages = dma_common_free_pages, 71462306a36Sopenharmony_ci}; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci/** 71762306a36Sopenharmony_ci * ps3_system_bus_release_device - remove a device from the system bus 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic void ps3_system_bus_release_device(struct device *_dev) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); 72362306a36Sopenharmony_ci kfree(dev); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci/** 72762306a36Sopenharmony_ci * ps3_system_bus_device_register - add a device to the system bus 72862306a36Sopenharmony_ci * 72962306a36Sopenharmony_ci * ps3_system_bus_device_register() expects the dev object to be allocated 73062306a36Sopenharmony_ci * dynamically by the caller. The system bus takes ownership of the dev 73162306a36Sopenharmony_ci * object and frees the object in ps3_system_bus_release_device(). 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ciint ps3_system_bus_device_register(struct ps3_system_bus_device *dev) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci int result; 73762306a36Sopenharmony_ci static unsigned int dev_ioc0_count; 73862306a36Sopenharmony_ci static unsigned int dev_sb_count; 73962306a36Sopenharmony_ci static unsigned int dev_vuart_count; 74062306a36Sopenharmony_ci static unsigned int dev_lpm_count; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (!dev->core.parent) 74362306a36Sopenharmony_ci dev->core.parent = &ps3_system_bus; 74462306a36Sopenharmony_ci dev->core.bus = &ps3_system_bus_type; 74562306a36Sopenharmony_ci dev->core.release = ps3_system_bus_release_device; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci switch (dev->dev_type) { 74862306a36Sopenharmony_ci case PS3_DEVICE_TYPE_IOC0: 74962306a36Sopenharmony_ci dev->core.dma_ops = &ps3_ioc0_dma_ops; 75062306a36Sopenharmony_ci dev_set_name(&dev->core, "ioc0_%02x", ++dev_ioc0_count); 75162306a36Sopenharmony_ci break; 75262306a36Sopenharmony_ci case PS3_DEVICE_TYPE_SB: 75362306a36Sopenharmony_ci dev->core.dma_ops = &ps3_sb_dma_ops; 75462306a36Sopenharmony_ci dev_set_name(&dev->core, "sb_%02x", ++dev_sb_count); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci case PS3_DEVICE_TYPE_VUART: 75862306a36Sopenharmony_ci dev_set_name(&dev->core, "vuart_%02x", ++dev_vuart_count); 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci case PS3_DEVICE_TYPE_LPM: 76162306a36Sopenharmony_ci dev_set_name(&dev->core, "lpm_%02x", ++dev_lpm_count); 76262306a36Sopenharmony_ci break; 76362306a36Sopenharmony_ci default: 76462306a36Sopenharmony_ci BUG(); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci dev->core.of_node = NULL; 76862306a36Sopenharmony_ci set_dev_node(&dev->core, 0); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci pr_debug("%s:%d add %s\n", __func__, __LINE__, dev_name(&dev->core)); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci result = device_register(&dev->core); 77362306a36Sopenharmony_ci return result; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_system_bus_device_register); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ciint ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci int result; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 78562306a36Sopenharmony_ci return -ENODEV; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci drv->core.bus = &ps3_system_bus_type; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci result = driver_register(&drv->core); 79062306a36Sopenharmony_ci pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); 79162306a36Sopenharmony_ci return result; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_civoid ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); 79962306a36Sopenharmony_ci driver_unregister(&drv->core); 80062306a36Sopenharmony_ci pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); 804